Jacoco Code Coverage

Java Jacoco Ant Maven

近期因工作需要本讥,需對代碼覆蓋率進行統(tǒng)計主籍,所以這篇就當做對這段時間學習的總結肾扰。
總得來說網(wǎng)上找到的資料都不系統(tǒng)突硝,不適合新手理解和參考榨惰,下面我就以我一個小白的親身體驗,將我
踩到的那些坑和遇到的那些疑惑記錄下來
(作為一名初學者挖胃,文章中可能會有錯誤或者理解偏差的地方雷袋,歡迎各位批評指正)

代碼覆蓋率工具調(diào)研信息如下:

  • 市場上主要代碼覆蓋率工具:
    • Emma
    • Cobertura
    • Jacoco
    • Clover(商用)

具體見下表:

工具 Jacoco Emma Cobertura
原理 使用 ASM 修改字節(jié)碼 修改 jar 文件密似,class 文件字節(jié)碼文件 基于 jcoverage,基于 asm 框架對 class 文件插樁
覆蓋粒度 行焙矛,類,方法残腌,指令薄扁,分支 行,類废累,方法邓梅,基本塊,指令邑滨,無分支覆蓋 項目日缨,包,類掖看,方法的語句覆蓋/分支覆蓋
插樁 on the fly匣距、offline on the fly面哥、offline offline,把統(tǒng)計代碼插入編譯好的class文件中
生成結果 在 Tomcat 的 catalina.sh 配置 javaangent 參數(shù)毅待,指出需要收集覆蓋率的文件尚卫,shutdown 時才收集,只能使用 kill 命令關閉 Tomcat尸红,不要使用 kill -9 html吱涉、xml、txt外里,二進制格式報表 html怎爵,xml
缺點 需要源代碼 1、需要 debug 版本盅蝗,并打來 build.xml 中的 debug 編譯項鳖链; 2、需要源代碼墩莫,且必須與插樁的代碼完全一致 1芙委、不能捕獲測試用例中未考慮的異常; 2狂秦、關閉服務器才能輸出覆蓋率信息(已有修改源代碼的解決方案灌侣,定時輸出結果;輸出結果之前設置了 hook故痊,會與某些服務器的 hook 沖突顶瞳,web 測試中需要將 cobertura.ser 文件來回 copy
性能 小巧 插入的字節(jié)碼信息更多
執(zhí)行方式 maven玖姑,ant愕秫,命令行 命令行 maven,ant
Jenkins 集成 生成 html 報告焰络,直接與 hudson 集成戴甩,展示報告,無趨勢圖 無法與 hudson 集成 有集成的插件闪彼,美觀的報告甜孤,有趨勢圖
報告實時性 默認關閉,可以動態(tài)從 jvm dump 出數(shù)據(jù) 可以不關閉服務器 默認是在關閉服務器時才寫結果
維護狀態(tài) 持續(xù)更新中 停止維護 停止維護

Tip:Jacoco 也是 Emma 團隊開發(fā)的



JaCoCo Java Code Coverage Library

Jacoco 是一個開源的覆蓋率工具畏腕。Jacoco 可以嵌入到 Ant 缴川、Maven 中,并提供了 EclEmma Eclipse 插件,也可以使用 Java Agent 技術監(jiān)控 Java 程序描馅。很多第三方的工具提供了對 Jacoco 的集成把夸,如:Sonar、Jenkins铭污、IDEA.

Java Counters

Jacoco 包含了多種尺度的覆蓋率計數(shù)器,包含指令級(Instructions,C0 coverage)恋日,分支(Branches,C1 coverage)膀篮、圈復雜度(Cyclomatic Complexity)、行(Lines)岂膳、方法(Non-abstract Methods)誓竿、類(Classes)。

? Instructions:Jacoco 計算的最小單位就是字節(jié)碼指令谈截。指令覆蓋率表明了在所有的指令中筷屡,哪些被執(zhí)行過以及哪些沒有被執(zhí)行。這項指數(shù)完全獨立于源碼格式并且在任何情況下有效傻盟,不需要類文件的調(diào)試信息速蕊。

? Branches:Jacoco 對所有的 if 和 switch 指令計算了分支覆蓋率。這項指標會統(tǒng)計所有的分支數(shù)量娘赴,并同時支出哪些分支被執(zhí)行规哲,哪些分支沒有被執(zhí)行。這項指標也在任何情況都有效诽表。異常處理不考慮在分支范圍內(nèi)唉锌。

      在有調(diào)試信息的情況下,分支點可以被映射到源碼中的每一行竿奏,并且被高亮表示袄简。
      紅色鉆石:無覆蓋,沒有分支被執(zhí)行泛啸。
      黃色鉆石:部分覆蓋绿语,部分分支被執(zhí)行。
      綠色鉆石:全覆蓋候址,所有分支被執(zhí)行吕粹。

? Cyclomatic Complexity:Jacoco 為每個非抽象方法計算圈復雜度,并也會計算每個類岗仑、包匹耕、組的復雜度。根據(jù) McCabe 1996 的定義荠雕,圈復雜度可以理解為覆蓋所有的可能情況最少使用的測試用例數(shù)稳其。這項參數(shù)也在任何情況下有效。

? Lines:該項指數(shù)在有調(diào)試信息的情況下計算炸卑。

      因為每一行代碼可能會產(chǎn)生若干條字節(jié)碼指令既鞠,所以我們用三種不同狀態(tài)表示行覆蓋率
      紅色背景:無覆蓋,該行的所有指令均無執(zhí)行盖文。
      黃色背景:部分覆蓋嘱蛋,該行部分指令被執(zhí)行。
      綠色背景:全覆蓋,該行所有指令被執(zhí)行浑槽。

? Methods:每一個非抽象方法都至少有一條指令蒋失。若一個方法至少被執(zhí)行了一條指令,就認為它被執(zhí)行過桐玻。因為 Jacoco 直接對字節(jié)碼進行操作篙挽,所以有些方法沒有在源碼顯示(比如某些構造方法和由編譯器自動生成的方法)也會被計入在內(nèi)。

? Classes:每個類中只要有一個方法被執(zhí)行镊靴,這個類就被認定為被執(zhí)行铣卡。同 5 一樣,有些沒有在源碼聲明的方法被執(zhí)行偏竟,也認定該類被執(zhí)行煮落。

Jacoco 原理

參考資料:

  1. 淺談代碼覆蓋率
  2. Jacoco 的原理
  3. Java 代碼覆蓋率工具 JaCoCo 原理篇


好了,廢話不多說踊谋,咱們直奔主題蝉仇,大家只要按照操作步驟執(zhí)行就可以

Jacoco 收集集成測試代碼覆蓋率

什么是集成測試?
  • 準備工作

  • 第一步:將下載下來的 zip 包與 Tomcat 服務放在一臺機器上

  • 第二步:在 [yourTomcatPath]/bin/catalina.sh 添加 Jacoco 插件殖蚕,指令如下??

     JAVA_OPTS="-javaagent:[yourPath/]jacocoagent.jar=includes=com.companyName.*,output=tcpserver,port=8044,address=100.44.44.144,append=true -Xverify:none"
    

    Tip:添加插件之前轿衔,須將的 Tomcat 服務停掉之后再添加,添加完之后睦疫,再啟動 Tomcat 服務

    參數(shù)說明:
       1. yourPath 是放 jacocoagent.jar 文件的目錄路徑害驹;那么 `jacocoagent.jar` 這個 `jar` 包的路徑就是在準備工作里下載下來的 `zip` 包,解壓之后的 `lib` 目錄下蛤育,如:'/jacoco-0.7.9/lib/jacocoagent.jar'
       2. includes 是指要收集哪些類(注意不要僅寫包名宛官,最后要寫.*),不寫的話默認是*瓦糕,會收集應用服務上所有的類底洗,包括服務器和其他中間件的類,一般要過濾(當然如果你愿意寫*也完全沒有問題刻坊,如:`includes=com.*` or `includes=*`)枷恕,如果要指定多個的話党晋,即這樣寫 `includes=com.package.1:com.package.2`(切記指定多個時中間用英文 `:` 隔開)谭胚;
       3. output 有 4 個值,分別是 file未玻、tcpserver灾而、tcpclient、mbean扳剿,默認是 file旁趟。使用 file 的方式只有在停掉應用服務的時候才能產(chǎn)生覆蓋率文件,而使用 tcpserver 的方式可以在不停止應用服務的情況下下載覆蓋率文件庇绽,后面會介紹如何使用 dump 方法來得到覆蓋率文件锡搜。
       4. address 是 IP 地址橙困,IP 就是 Tomcat 服務器的機器的 IP,至于是寫 `服務器本機的 IP` 還是寫 `127.0.0.1` 要看情況
           1) 如果是在 Tomcat 服務器上執(zhí)行 `ant dump` 的話耕餐,就直接寫 `address=127.0.0.1`
           2) 如果執(zhí)行 `ant dump` 不是在 Tomcat 服務器上執(zhí)行的凡傅,就得寫服務器本機的IP(切記)
       5. port 是端口(端口比較隨便,找個能用的端口就行肠缔,直接我為什么將端口寫成 `8044`夏跷,我的想法是 `BUG 死死` 與 `8044` 挺配的,所以就用它作為端口號了)
    (`address` 和 `port` 是使用 tcpserver 方式需要的 2 個參數(shù)明未,也是執(zhí)行 ant dump 方法必須要用到的槽华。)
       6. append 表示覆蓋率數(shù)據(jù)的追加方式,默認為 true趟妥∶ㄌ客戶端在執(zhí)行 dump 操作時,如果該 exec 覆蓋率文件已存在披摄,那么該輪的覆蓋率數(shù)據(jù)會直接在文本末尾進行追加懂鸵,因此會導致覆蓋率數(shù)據(jù)文件越來越大。如果改為 false行疏,則客戶端執(zhí)行 dump 操作時會直接清空原覆蓋率文件的內(nèi)容匆光,保證該覆蓋率文件只有該輪的覆蓋率數(shù)據(jù)。
       7. `-Xverify:none`:這個參數(shù)是防止啟動主程序異常才加的(非強制酿联,可以不加)
    

    Tip:更多參數(shù)說明终息,請點擊 這里

啟動 Tomcat 服務之后,ps 一下贞让,如果在 Tomcat 服務中有 jacocoagent 這個服務的話
那么恭喜你周崭,你成功了!T拧续镇!
  • 第三步:獲取報告 ant dump(也是就上文中提到的,特別提醒:這里使用 ant 命令销部,和你的代碼工程使用什么編譯工具編譯的沒有一點關系摸航,不要混淆)
    build.xml 文件內(nèi)容如下??
<?xml version="1.0" encoding="UTF-8"?>
<project name="Jacoco" xmlns:jacoco="antlib:org.jacoco.ant" default="jacoco">   
    <property name="jacocoantPath" value="[yourPath/]jacocoant.jar"/>
    <property name="integrationJacocoexecPath" value="./jacoco-integration.exec"/>
    
    <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
      <classpath path="${jacocoantPath}" />
    </taskdef>
    
    <target name="dump">
        <jacoco:dump address="100.44.44.144" port="8044" reset="false" destfile="${integrationJacocoexecPath}" append="true"/>
    </target>
</project>
`.exec`:二進制文件,Jacoco 就是根據(jù)這個文件生成最終的報告
`destfile`:是指生成的覆蓋率文件路徑

Tip:
build.xml 只需修改三個點舅桩,就可以直接拿去用
第一個修改點:補全 `jacocoant.jar` 路徑酱虎。(那么 `jacocoant.jar` 在哪?對于這個問題擂涛,或許會有疑問读串,當然,如果細心的小伙伴就會很輕易的發(fā)現(xiàn) `jacocoant.jar` 的位置,其實也就在準備工作中所下載的 `zip` 包里面恢暖,與 `jacocoagent.jar` 在同級目錄 `lib` 文件夾下)
第二個修改點:修改 IP 地址(IP 須與 `catalina.sh` 中添加的一致)
第三個修改點:修改端口號(與IP一樣排监,端口號須與 `catalina.sh` 中添加的一致)

Frequently Asked Questions:
雖然得到了集成測試的覆蓋率文件,但是需要應用服務器上的類文件才能產(chǎn)出相應的覆蓋率報告杰捂,如果類文件是其他 JVM 編譯的社露,產(chǎn)出的報告覆蓋率是 0%。
有 2 種方法可以得到覆蓋率文件所需的 class 文件:
1. 將應用服務部署的包(ear 或 war 或 jar)包下載下來之后解壓琼娘,即可得到對應的 class 文件峭弟;
2. 在前面做單元測試之后,可以將 class 文件打成一個 zip 包脱拼,然后上傳到服務器瞒瘸,最后在需要的時候去服務器上取。

修改好了熄浓,那么我們來測試一下情臭,終端進入 build.xml 所在的目錄,執(zhí)行:ant dump 或者 ant dump -buildfile [yourPath/]build.xml

ant dump

成功之后赌蔑,接下來就是 Jenkins 集成 jacoco 實現(xiàn)代碼覆蓋率俯在,詳見:Jenkins + Jacoco
持續(xù)集成代碼覆蓋率

是不是只有上面的這一種方式呢?當然不是娃惯!
第二種方式(不推薦):
JAVA_OPTS="-javaagent:[yourPath/]jacocoagent.jar=destfile=[storagePath/]jacoco.exec
同樣是加載 cataline.sh 文件中跷乐,除了獲取報告的方式上面的不一樣之前,其余步驟都一樣

獲取報告:
功能測試或者接口自動化后趾浅,需要獲取報告的話愕提,需關閉 Tomcat 獲取結果文件 `jacoco.exec`,使用 kill [PID]皿哨,之后到你保存的路徑下就能看到 `jacoco.exec` 文件(切記不要使用 kill -9 [PID]浅侨,否則不能生成結果)
不推薦這種方式的理由:如果使用這種方式的話,不好做持續(xù)集成证膨,因為 jenkins 服務器基本上都是和部署代碼的服務器分開的如输,所以要從遠程服務器取結果的話還是選擇上面的方式
Q:那現(xiàn)在可能又有同學會問,這個報告只能在 `Jenkins` 上面生成嗎央勒?
A:當然也可以在本地生成了不见,附上代碼,如下??
<?xml version="1.0" encoding="UTF-8"?>
<project name="Jacoco" xmlns:jacoco="antlib:org.jacoco.ant" default="jacoco">
    <!--Jacoco 的安裝路徑-->
  <property name="jacocoantPath" value="[yourPath/]jacocoant.jar"/>
  <!--最終生成 .exec 文件的路徑订歪,Jacoco 就是根據(jù)這個文件生成最終的報告的-->
  <property name="jacocoexecPath" value="[yourPath/]jacoco.exec"/>
    <!--生成覆蓋率報告的路徑-->
  <property name="reportfolderPath" value="[storageReportPath]"/>
  <!--遠程 Tomcat 服務的 ip 地址-->
  <property name="server_ip" value="100.44.44.144"/>
  <!--前面配置的遠程 Tomcat 服務打開的端口脖祈,要跟上面配置的一樣-->
  <property name="server_port" value="8044"/>
  <!--源代碼路徑-->
  <property name="checkOrderSrcPath" value="[srcPath]" />
  <!--.class 文件路徑-->
  <property name="checkOrderClasspath" value="[classPath]" />

  <!--讓 ant 知道去哪兒找 Jacoco-->
  <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
      <classpath path="${jacocoantPath}" />
  </taskdef>

  <!--dump 任務:
      根據(jù)前面配置的 ip 地址肆捕,和端口號刷晋,
      訪問目標 Tomcat 服務,并生成 .exec 文件。-->
  <target name="dump">
      <jacoco:dump address="${server_ip}" reset="false" destfile="${jacocoexecPath}" port="${server_port}" append="true"/>
  </target>
  
  <!--jacoco 任務:
      根據(jù)前面配置的源代碼路徑和 .class 文件路徑眼虱,
      根據(jù) dump 后喻奥,生成的 .exec 文件,生成最終的 html 覆蓋率報告捏悬。-->
  <target name="report">
      <delete dir="${reportfolderPath}" />
      <mkdir dir="${reportfolderPath}" />
      
      <jacoco:report>
          <executiondata>
              <file file="${jacocoexecPath}" />
          </executiondata>
              
          <structure name="JaCoCo Report">
              <group name="Check Order related">           
                  <classfiles>
                      <fileset dir="${checkOrderClasspath}">
                          <!-- 過濾不必要的文件 -->
                          <exclude name="**/R.class"/>
                          <exclude name="**/R$*.class"/>
                          <exclude name="**/*$ViewInjector*.*"/>
                          <exclude name="**/BuildConfig.*"/>
                          <exclude name="**/Manifest*.*"/>
                      </fileset>
                  </classfiles>
                  <sourcefiles encoding="UTF-8">
                      <fileset dir="${checkOrderSrcPath}" />
                  </sourcefiles>
              </group>
          </structure>
          <html destdir="${reportfolderPath}" encoding="UTF-8" />
          <csv destfile="${reportfolderPath}/coverage-report.csv" encoding="UTF-8"/>
          <xml destfile="${reportfolderPath}/coverage-report.xml" encoding="UTF-8"/>         
      </jacoco:report>
  </target>
</project>


Jacoco 收集單元測試代碼覆蓋率

  • pom.xml 配置 plugin
           <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.7.7.201606060606</version>
                <configuration>
                    <!--指定生成 .exec 文件的存放位置-->
                    <destFile>target/coverage-reports/jacoco-unit.exec</destFile>
                    <!--Jacoco 是根據(jù) .exec 文件生成最終的報告撞蚕,所以需指定 .exec 的存放路徑-->
                    <dataFile>target/coverage-reports/jacoco-unit.exec</dataFile>
                </configuration>
                <executions>
                    <execution>
                        <id>jacoco-initialize</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>jacoco-site</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
Demo 工程下載
  • 下載之后解壓,直接進入工程目錄过牙,運行 mvn test甥厦,接著你將看到如下圖所示的文件
    image.png

其中 jacoco-unit.exec 是二進制文件,就不多說了寇钉,而 index.html 就是代碼覆蓋率報告刀疙,如下圖??

jacoco.xml
report
report
report
Tip:
綠色部分:完全覆蓋
黃色部分:條件覆蓋
紅色部分:未覆蓋
  • 合并集成測試代碼覆蓋率和單元測試代碼覆蓋率,build.xml 代碼如下??
<?xml version="1.0" encoding="UTF-8"?>
    <project name="Jacoco" xmlns:jacoco="antlib:org.jacoco.ant" default="jacoco">
    <property name="baseDir" value="[yourExecFilePath]"/>   
    <property name="jacocoantPath" value="[yourPath/]jacocoant.jar"/>
    <property name="allJacocoexecPath" value="./jacoco-all.exec"/>
    
    <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
      <classpath path="${jacocoantPath}" />
    </taskdef>

    <target name="merge">
        <jacoco:merge destfile="${allJacocoexecPath}">
        <fileset dir="${baseDir}" includes="*.exec"/>
        </jacoco:merge>
    </target>
</project>

只要將這份 build.xml 放在代碼的根目錄下扫倡,執(zhí)行 ant merge 就可將所有以 .exec 文件合并谦秧,重新生成名為 jacoco-all.exec 的二進制文件,當然也可以將文章中的兩份 build.xml 文件合并撵溃,代碼如下??

<?xml version="1.0" encoding="UTF-8"?>
<project name="Jacoco" xmlns:jacoco="antlib:org.jacoco.ant" default="jacoco">
    <property name="jacocoantPath" value="[yourpath/]jacocoant.jar"/>
    <property name="baseDir" value="[yourExecFilePath]"/>
    <property name="integrationJacocoexecPath" value="./jacoco-integration.exec"/>
    <property name="allJacocoexecPath" value="./jacoco-all.exec"/>
    
    <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
      <classpath path="${jacocoantPath}" />
    </taskdef>
    
    <target name="dump">
        <jacoco:dump address="100.44.44.144" port="8044" reset="true" destfile="${integrationJacocoexecPath}" append="false"/>
    </target>

    <target name="merge">
        <jacoco:merge destfile="${allJacocoexecPath}">
        <fileset dir="${baseDir}" includes="*.exec"/>
        </jacoco:merge>
    </target>
</project>
分別執(zhí)行:
    `ant dump` & `ant merge`
          or 
    `ant dump -buildfile [yourpath/]build.xml` & `ant merge -buildfile [yourpath/]build.xml`
這樣生成的代碼覆蓋率報告中既包含集成測試代碼覆蓋率疚鲤,又包含單元測試代碼覆蓋率的報告

將 .exec 文件合并之后,參照上文中提到的 Jenkins + Jacoco 持續(xù)集成代碼覆蓋率 這篇文章缘挑,將它與 Jenkins 集成集歇。當然還可以借助于 Sonar 將靜態(tài)代碼檢查的數(shù)據(jù)與代碼覆蓋率同步到 SonarQube 平臺,詳見:SonarQube & SonarQube Scanner

如果在閱讀或者實踐的過程中遇到什么問題语淘,歡迎在下方評論
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鬼悠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子亏娜,更是在濱河造成了極大的恐慌焕窝,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件维贺,死亡現(xiàn)場離奇詭異它掂,居然都是意外死亡,警方通過查閱死者的電腦和手機溯泣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門虐秋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人垃沦,你說我怎么就攤上這事客给。” “怎么了肢簿?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵靶剑,是天一觀的道長蜻拨。 經(jīng)常有香客問我,道長桩引,這世上最難降的妖魔是什么缎讼? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮坑匠,結果婚禮上血崭,老公的妹妹穿的比我還像新娘。我一直安慰自己厘灼,他們只是感情好夹纫,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著设凹,像睡著了一般捷凄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上围来,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天跺涤,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛蚣录,可吹牛的內(nèi)容都是我干的验烧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起退腥,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎再榄,沒想到半個月后狡刘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡困鸥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年嗅蔬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疾就。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡澜术,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出猬腰,到底是詐尸還是另有隱情鸟废,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布姑荷,位于F島的核電站盒延,受9級特大地震影響缩擂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜兰英,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一撇叁、第九天 我趴在偏房一處隱蔽的房頂上張望供鸠。 院中可真熱鬧畦贸,春花似錦、人聲如沸楞捂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寨闹。三九已至胶坠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間繁堡,已是汗流浹背沈善。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留椭蹄,地道東北人闻牡。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像绳矩,于是被迫代替她去往敵國和親罩润。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容