Jasmine Unit Test

Unit Test

  • 單元測試概念(Unit Testing)

    又稱為模塊測試, 是針對(duì)程序模塊(軟件設(shè)計(jì)的最小單位)來進(jìn)行正確性檢驗(yàn)的測試工作。程序單元是應(yīng)用的最小可測試部件蜈缤。在過程化編程中踩窖,一個(gè)單元就是單個(gè)程序翘县、函數(shù)诺擅、過程等市袖;對(duì)于面向?qū)ο缶幊蹋钚卧褪欠椒ㄏ苹ⅲɑ悾ǔ悾┝瓒ⅰ⒊橄箢惛斗恪⒒蛘吲缮悾ㄗ宇悾┲械姆椒ā?/p>

  • 單元測試必要性

    隨著項(xiàng)目規(guī)模的增加烹玉,函數(shù)续捂、方法孩灯、變量都在遞增,維護(hù)的難度不斷加大僧凰,以及測試提出的各種bug導(dǎo)致修改代碼的時(shí)候會(huì)將原本整潔的代碼變得混亂掂榔。
    經(jīng)常出現(xiàn)同一個(gè)接口以不同的名稱出現(xiàn)在不同的控制器中继效,這個(gè)時(shí)候往往會(huì)去重構(gòu)代碼,但是重構(gòu)代碼的時(shí)候沒人會(huì)保證自己將萬無一失装获,重構(gòu)的代碼還是正確的瑞信,方法一樣跑通等等。這個(gè)時(shí)候就需要單元測試了穴豫,單元測試是一個(gè)衡量標(biāo)準(zhǔn)凡简,告訴開發(fā)人員這么做是否將改變結(jié)果。保證重構(gòu)后的代碼的兼容性精肃,減少人力測試的過程秤涩,降低維護(hù)成本。

<h2>Jasmine</h2>

Jasmine是一個(gè)behavior-driven development ( 行為驅(qū)動(dòng)開發(fā) ) 測試框架司抱, 不依賴于任何其他JavaScript框架筐眷, 不依賴DOM, 并且有很簡潔的語法讓你能夠很輕松的編寫單元測試习柠。它既可以在html文件中運(yùn)行匀谣,也可以和jsTestDriver整合,在jsTestDriver中運(yùn)行资溃。
  • BDD 行為驅(qū)動(dòng)開發(fā)武翎,是一種新的敏捷開發(fā)方法。相對(duì)于TDD(測試驅(qū)動(dòng)開發(fā))肉拓,它更趨向于需求后频,需要共同利益者的參與,強(qiáng)調(diào)用戶故事和行為;是面向開發(fā)者、QA卑惜、非技術(shù)人員或商業(yè)參與者共同參與和理解的開發(fā)活動(dòng)膏执,而不是TDD簡單地只關(guān)注開發(fā)者的方法論;

  • TDD測試驅(qū)動(dòng)開發(fā)露久,是一種不同于傳統(tǒng)軟件開發(fā)流程:開發(fā)結(jié)束再測試介入的新型開發(fā)方法更米。要求把項(xiàng)目按功能點(diǎn)劃分,在編寫每個(gè)功能點(diǎn)前先編寫測試代碼毫痕,然后再編寫使測試通過的功能代碼征峦,通過測試來推動(dòng)整個(gè)開發(fā)工作。

<h2>搭建環(huán)境</h2>

<h4>1.下載源文件</h4>

jasmine源文件下載地址

圖1.png
下載jasmine-standlone-2.5.0.zip即可消请。這是一個(gè)范例栏笆,但是可以直接使用。運(yùn)行起來如下圖顯示:
運(yùn)行圖

<h4>2.使用</h4>
將下載下來的文件夾中l(wèi)ib文件夾下的jasmine-2.5.0文件夾直接拖入你所需要用的項(xiàng)目臊泰。在index.html 中引入下面幾句

  <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.5.0/jasmine_favicon.png">
  <link rel="stylesheet" href="lib/jasmine-2.5.0/jasmine.css">

  <script src="lib/jasmine-2.5.0/jasmine.js"></script>
  <script src="lib/jasmine-2.5.0/jasmine-html.js"></script>
  <script src="lib/jasmine-2.5.0/boot.js"></script>

之后便可以直接創(chuàng)建對(duì)應(yīng)的測試用例js文件了蛉加。

<h2>jasmine基礎(chǔ)語法</h2>
一個(gè)簡單的例子

describe("A suite", function() {  
    it("contains spec with an expectation", function() {  
        expect(true).toBe(true);  
    });  
}); 

<h3>1.兩個(gè)核心方法</h3>

  • <h4>describe方法</h4>
    describe是jasmine用于描述測試集(Test Suite)的全局函數(shù),作為測試集的開始缸逃,一般有兩個(gè)參數(shù)针饥,字符串和方法。字符串作為特定用例組的名字和標(biāo)題需频。方法是包含實(shí)現(xiàn)用例組的代碼丁眼。一個(gè)測試集合可以包含多個(gè)spec(測試點(diǎn))。
  • <h4>it方法</h4>
    jasmine中用方法it來開始specs昭殉。it方法和describe方法類似苞七, 同樣有兩個(gè)參數(shù),一個(gè)String饲化,一個(gè)function莽鸭;String用來描述測試點(diǎn)(spec),function是具體的測試代碼吃靠。

示例代碼

describe("This is an exmaple suite", function() {
  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
    expect(false).toBe(false);
    expect(false).not.toBe(true);
  });
});

<h3>2.四個(gè)核心概念</h3>
<h4>Jasmine四個(gè)核心概念:</h4>

  • 分組(Suites)
  • 用例(Specs)
  • 期望(Expectations)
  • 匹配(Matchers)
  • 分組(Suites)

    Suites可以理解為一組測試用例硫眨,以函數(shù)describe(string,function)封裝,describe函數(shù)接受兩個(gè)參數(shù)巢块,一個(gè)字符串和一個(gè)函數(shù)礁阁。字符串是這個(gè)Suites的名字或標(biāo)題(通常描述下測試內(nèi)容),函數(shù)是實(shí)現(xiàn)Suites的代碼塊族奢。一個(gè)Suite可以包含多個(gè)Specs姥闭,一個(gè)Specs可以包括多個(gè)expect

  • 用例(Specs)

    Specs可以理解為一個(gè)測試用例,使用全局的Jasmin函數(shù)it創(chuàng)建越走。和describe一樣接受兩個(gè)參數(shù)棚品,一個(gè)字符串和一個(gè)函數(shù)靠欢,函數(shù)就是要執(zhí)行的測試代碼,字符串就是測試用例的名字铜跑。一個(gè)Spec可以包含多個(gè)expectations來測試代碼门怪。

  • 期望(Expectations)

    Expectations由expect 函數(shù)創(chuàng)建。接受一個(gè)參數(shù)锅纺。和Matcher一起聯(lián)用掷空,設(shè)置測試的預(yù)期值。返回ture或false囤锉。
    在分組(describe)中可以寫多個(gè)測試用例(it)坦弟,也可以再進(jìn)行分組(describe),在測試用例(it)中定義期望表達(dá)式(expect)和匹配判斷(toBe)官地∧鸢看一個(gè)簡單的Demo:

describe("A suite", function() {//suites
    var a;
    it("A spec", function() {//spec
      a = true;
      expect(a).toBe(true);//expectations
    });
    
    describe("a suite", function() {//inner suites
           it("a spec", function() {//spec
           expect(a).toBe(true);//expectations
        });
  });
});

  • 匹配(Matchers)

    Matcher實(shí)現(xiàn)斷言的比較操作,一個(gè)“期望值”與“實(shí)際值”的對(duì)比区丑,如果結(jié)果為true拧粪,則通過測試修陡,反之沧侥,則失敗。每一個(gè)matcher都能通過not執(zhí)行否定判斷魄鸦。
expect(a).toBe(true);//期望變量a為true
expect(a).toEqual(true);//期望變量a等于true
expect(a).toMatch(/reg/);//期望變量a匹配reg正則表達(dá)式宴杀,也可以是字符串
expect(a.foo).toBeDefined();//期望a.foo已定義
expect(a.foo).toBeUndefined();//期望a.foo未定義
expect(a).toBeNull();//期望變量a為null
expect(a.isMale).toBeTruthy();//期望a.isMale為真
expect(a.isMale).toBeFalsy();//期望a.isMale為假
expect(true).toEqual(true);//期望true等于true
expect(a).toBeLessThan(b);//期望a小于b
expect(a).toBeGreaterThan(b);//期望a大于b
expect(a).toThrowError(/reg/);//期望a方法拋出異常,異常信息可以是字符串拾因、正則表達(dá)式旺罢、錯(cuò)誤類型以及錯(cuò)誤類型和錯(cuò)誤信息
expect(a).toThrow();//期望a方法拋出異常
expect(a).toContain(b);//期望a(數(shù)組或者對(duì)象)包含b
自定義Matcher(被稱為Matcher Factories)實(shí)質(zhì)上是一個(gè)函數(shù)(該函數(shù)的參數(shù)可以為空),該函數(shù)返回一個(gè)閉包绢记,該閉包的本質(zhì)是一個(gè)compare函數(shù)扁达,compare函數(shù)接受2個(gè)參數(shù):actual value 和 expected value。  
compare函數(shù)必須返回一個(gè)帶pass屬性的結(jié)果Object蠢熄,pass屬性是一個(gè)Boolean值跪解,表示該Matcher的結(jié)果(為true表示該Matcher實(shí)際值與預(yù)期值匹配,為false表示不匹配)签孔,也就是說叉讥,實(shí)際值與預(yù)期值具體的比較操作的結(jié)果,存放于pass屬性中饥追。  
其他matchers:

jasmine.any(Class)--傳入構(gòu)造函數(shù)或者類返回?cái)?shù)據(jù)類型作為期望值图仓,返回true表示實(shí)際值和期望值數(shù)據(jù)類型相同:

it("matches any value", function() {
    expect({}).toEqual(jasmine.any(Object));
    expect(12).toEqual(jasmine.any(Number));
});

jasmine.anything()--如果實(shí)際值不是null或者undefined則返回true:

it("matches anything", function() {
    expect(1).toEqual(jasmine.anything());
});

jasmine.objectContaining({key:value})--實(shí)際數(shù)組只要匹配到有包含的數(shù)值就算匹配通過:

foo = {
      a: 1,
      b: 2,
      bar: "baz"
};
expect(foo).toEqual(jasmine.objectContaining({bar: "baz"}));

jasmine.arrayContaining([val1,val2,...])--stringContaining可以匹配字符串的一部分也可以匹配對(duì)象內(nèi)的字符串:

expect({foo: 'bar'}).toEqual({foo: jasmine.stringMatching(/^bar$/)});
expect('foobarbaz').toEqual({foo: jasmine.stringMatching('bar')});

3.Setup和Teardown方法

為了減少重復(fù)性的代碼,jasmine提供了beforeEach但绕、afterEach救崔、beforeAll、afterAll方法。 
  • beforeEach() :在describe函數(shù)中每個(gè)Spec執(zhí)行之前執(zhí)行六孵;
  • afterEach() :在describe函數(shù)中每個(gè)Spec執(zhí)行之后執(zhí)行;
  • beforeAll() :在describe函數(shù)中所有的Specs執(zhí)行之前執(zhí)行碳竟,且只執(zhí)行一次
  • afterAll () : 在describe函數(shù)中所有的Specs執(zhí)行之后執(zhí)行,且只執(zhí)行一次
describe("A spec (with setup and tear-down)", function () {
    var foo;    
    //beforeAll 在所有的it方法執(zhí)行之前執(zhí)行一次
    beforeAll(function () { 
           foo = 1;       
          console.log("beforeAll run");   
   });    

   //afterAll 在所有的it方法執(zhí)行之后執(zhí)行一次
    afterAll(function () {       
        foo = 0;        
        console.log("afterAll run");   
    });   

  //beforeEach 在每個(gè)it方法執(zhí)行之前都執(zhí)行一次
   beforeEach(function () {        
        console.log("beforeEach run");   
   });    

 //afterEach 在每個(gè)it方法執(zhí)行之后都執(zhí)行一次
  afterEach(function () {        
      console.log("afterEach run");    
  });    

  it("is just a function,so it can contain any code", function () {       
       expect(foo).toEqual(1);    
  });   

  it("can have more than one expectation", function () {
       expect(foo).toEqual(1);
       expect(true).toEqual(true);    
  });
});

結(jié)果如圖所示:

結(jié)果

4.describe函數(shù)的嵌套

每個(gè)嵌套的**describe**函數(shù)狸臣,都可以有自己的**beforeEach**莹桅,**afterEach**函數(shù)。  
在執(zhí)行每個(gè)內(nèi)層**Spec**時(shí)烛亦,都會(huì)按嵌套的由外及內(nèi)的順序執(zhí)行每個(gè)**beforeEach**函數(shù)诈泼,所以內(nèi)層**Sepc**可以訪問到外層**Sepc**中的**beforeEach**中的數(shù)據(jù)。類似的煤禽,當(dāng)內(nèi)層**Spec**執(zhí)行完成后铐达,會(huì)按由內(nèi)及外的順序執(zhí)行每個(gè)**afterEach**函數(shù)。
describe("A spec", function() {
  var foo;

  beforeEach(function() {
    foo = 0;
    foo += 1;
  });

  afterEach(function() {
    foo = 0;
  });

  it("is just a function, so it can contain any code", function() {
    expect(foo).toEqual(1);
  });

  it("can have more than one expectation", function() {
    expect(foo).toEqual(1);
    expect(true).toEqual(true);
  });

  describe("nested inside a second describe", function() {
    var bar;

    beforeEach(function() {
      bar = 1;
    });

    it("can reference both scopes as needed", function() {
      expect(foo).toEqual(bar);
    });
  });
});

5.禁用Suites,掛起Specs

**Suites**可以被**Disabled**檬果。在**describe**函數(shù)名之前添加**x**即可將**Suite**禁用瓮孙。  
被**Disabled**的**Suites**在執(zhí)行中會(huì)被跳過,該**Suite**的結(jié)果也不會(huì)顯示在結(jié)果集中选脊。  
xdescribe("A spec", function() {
  var foo;

  beforeEach(function() {
    foo = 0;
    foo += 1;
  });

  it("is just a function, so it can contain any code", function() {
    expect(foo).toEqual(1);
  });
});
有3種方法可以將一個(gè)Spec標(biāo)記為Pending杭抠。被Pending的Spec不會(huì)被執(zhí)行,但是Spec的名字會(huì)在結(jié)果集中顯示恳啥,只是標(biāo)記為Pending偏灿。
  • 如果在Spec函數(shù)it的函數(shù)名之前添加x(xit),那么該Spec就會(huì)被標(biāo)記為Pending钝的。
  • 一個(gè)沒有定義函數(shù)體的Sepc也會(huì)在結(jié)果集中被標(biāo)記為Pending翁垂。
  • 如果在Spec的函數(shù)體中調(diào)用pending()函數(shù),那么該Spec也會(huì)被標(biāo)記為Pending硝桩。pending()函數(shù)接受一個(gè)字符串參數(shù)沿猜,該參數(shù)會(huì)在結(jié)果集中顯示在PENDING WITH MESSAGE:之后,作為為何被Pending的原因碗脊。
describe("Pending specs", function() {

  xit("can be declared 'xit'", function() {
    expect(true).toBe(false);
  });

  it("can be declared with 'it' but without a function");
  
  it("can be declared by calling 'pending' in the spec body", function() {
    expect(true).toBe(false);
    pending('this is why it is pending');
  });
});

6.Spy追蹤

Jasmine具有函數(shù)的追蹤和反追蹤的雙重功能啼肩,這東西就是Spy。Spy能夠存儲(chǔ)任何函數(shù)調(diào)用記錄和傳入的參數(shù)望薄,Spy只存在于describe和it中疟游,在spec執(zhí)行完之后銷毀。

describe("A spy", function() {
  var foo, bar = null;
  beforeEach(function() {
    foo = {
      setBar: function(value) {
        bar = value;
      }
    };
    spyOn(foo, 'setBar');//給foo對(duì)象的setBar函數(shù)綁定追蹤
    foo.setBar(123);
    foo.setBar(456, 'another param');
  });
  it("tracks that the spy was called", function() {
    expect(foo.setBar).toHaveBeenCalled();//toHaveBeenCalled用來匹配測試函數(shù)是否被調(diào)用過
  });
  it("tracks all the arguments of its calls", function() {
    expect(foo.setBar).toHaveBeenCalledWith(123);//toHaveBeenCalledWith用來匹配測試函數(shù)被調(diào)用時(shí)的參數(shù)列表
    expect(foo.setBar).toHaveBeenCalledWith(456, 'another param');//期望foo.setBar已經(jīng)被調(diào)用過痕支,且傳入?yún)?shù)為[456, 'another param']
  });
  it("stops all execution on a function", function() {
    expect(bar).toBeNull();//用例沒有執(zhí)行foo.setBar,bar為null
  });
});

and.callThrough--spy鏈?zhǔn)秸{(diào)用and.callThrough后颁虐,在獲取spy的同時(shí),調(diào)用實(shí)際的函數(shù)卧须。

describe("A spy, when configured to call through", function() {
  var foo, bar, fetchedBar;
  beforeEach(function() {
    foo = {
      setBar: function(value) {
        bar = value;
      },
      getBar: function() {
        return bar;
      }
    };
    spyOn(foo, 'getBar').and.callThrough();//調(diào)用and.callThrough方法
    foo.setBar(123);
    fetchedBar = foo.getBar();//因?yàn)閍nd.callThrough另绩,這里執(zhí)行的是foo.getBar方法儒陨,而不是spy的方法
  });
  it("tracks that the spy was called", function() {
    expect(foo.getBar).toHaveBeenCalled();
  });
  it("should not effect other functions", function() {
    expect(bar).toEqual(123);
  });
  it("when called returns the requested value", function() {
    expect(fetchedBar).toEqual(123);
  });
});

and.returnValue--spy鏈?zhǔn)秸{(diào)用and.returnValue 后,任何時(shí)候調(diào)用該方法都只會(huì)返回指定的值笋籽,

describe("A spy, when configured to fake a return value", function() {
  var foo, bar, fetchedBar;
  beforeEach(function() {
    foo = {
      setBar: function(value) {
        bar = value;
      },
      getBar: function() {
        return bar;
      }
    };
    spyOn(foo, "getBar").and.returnValue(745);//指定返回值為745
    foo.setBar(123);
    fetchedBar = foo.getBar();
  });
  it("tracks that the spy was called", function() {
    expect(foo.getBar).toHaveBeenCalled();
  });
  it("should not effect other functions", function() {
    expect(bar).toEqual(123);
  });
  it("when called returns the requested value", function() {
    expect(fetchedBar).toEqual(745);//默認(rèn)返回指定的returnValue值
  });
});

and.callFake--spy鏈?zhǔn)教砑觓nd.callFake相當(dāng)于用新的方法替換spy的方法

describe("A spy, when configured with an alternate implementation", function() {
  var foo, bar, fetchedBar;
  beforeEach(function() {
    foo = {
      setBar: function(value) {
        bar = value;
      },
      getBar: function() {
        return bar;
      }
    };
    spyOn(foo, "getBar").and.callFake(function() {//指定callFake方法
      return 1001;
    });
    foo.setBar(123);
    fetchedBar = foo.getBar();
  });
  it("tracks that the spy was called", function() {
    expect(foo.getBar).toHaveBeenCalled();
  });
  it("should not effect other functions", function() {
    expect(bar).toEqual(123);
  });
  it("when called returns the requested value", function() {
    expect(fetchedBar).toEqual(1001);//執(zhí)行callFake方法蹦漠,返回1001
  });
});

and.throwError--spy鏈?zhǔn)秸{(diào)用and.callError后,任何時(shí)候調(diào)用該方法都會(huì)拋出異常錯(cuò)誤信息:

describe("A spy, when configured to throw an error", function() {
  var foo, bar;
  beforeEach(function() {
    foo = {
      setBar: function(value) {
        bar = value;
      }
    };
    spyOn(foo, "setBar").and.throwError("error");//指定throwError
  });
  it("throws the value", function() {
    expect(function() {
      foo.setBar(123)
    }).toThrowError("error");//拋出錯(cuò)誤異常
  });
});

and.stub--spy恢復(fù)到原始狀態(tài)车海,不執(zhí)行任何操作笛园。直接看下代碼:

describe("A spy", function() {
  var foo, bar = null;
  beforeEach(function() {
    foo = {
      setBar: function(value) {
        bar = value;
      }
    };
    spyOn(foo, 'setBar').and.callThrough();
  });
  it("can call through and then stub in the same spec", function() {
    foo.setBar(123);
    expect(bar).toEqual(123);
    foo.setBar.and.stub();//把foo.setBar設(shè)置為原始狀態(tài),and.callThrough無效
    bar = null;
    foo.setBar(123);//執(zhí)行賦值無效
    expect(bar).toBe(null);
  });
});

Spy的其他方法

.calls.any():記錄spy是否被訪問過侍芝,如果沒有研铆,則返回false,否則州叠,返回true棵红;
.calls.count():記錄spy被訪問過的次數(shù);
.calls.argsFor(index):返回指定索引的參數(shù)咧栗;
.calls.allArgs():返回所有函數(shù)調(diào)用的參數(shù)記錄數(shù)組逆甜;
.calls.all ():返回所有函數(shù)調(diào)用的上下文、參數(shù)和返回值致板;
.calls.mostRecent():返回最近一次函數(shù)調(diào)用的上下文交煞、參數(shù)和返回值;
.calls.first():返回第一次函數(shù)調(diào)用的上下文可岂、參數(shù)和返回值错敢;
.calls.reset():清除spy的所有調(diào)用記錄;
還有幾種方法缕粹,諸如異步,ajax等等纸淮,我還只是入門平斩,不甚了解,demo的話這之后我弄好會(huì)放上來咽块。

參考:

官方文檔
jasmine測試框架簡介
JavaScript單元測試框架-Jasmine
JavaScript 單元測試框架:Jasmine 初探
web前端開發(fā)七武器—Jasmine入門教程(上)
前端測試-jasmine
開啟JavaScript測試之路--Jasmine

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绘面,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子侈沪,更是在濱河造成了極大的恐慌揭璃,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亭罪,死亡現(xiàn)場離奇詭異瘦馍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)应役,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門情组,熙熙樓的掌柜王于貴愁眉苦臉地迎上來燥筷,“玉大人,你說我怎么就攤上這事院崇∷撩ィ” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵底瓣,是天一觀的道長谢揪。 經(jīng)常有香客問我,道長捐凭,這世上最難降的妖魔是什么键耕? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮柑营,結(jié)果婚禮上屈雄,老公的妹妹穿的比我還像新娘。我一直安慰自己官套,他們只是感情好酒奶,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奶赔,像睡著了一般惋嚎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上站刑,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天另伍,我揣著相機(jī)與錄音,去河邊找鬼绞旅。 笑死摆尝,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的因悲。 我是一名探鬼主播堕汞,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼晃琳!你這毒婦竟也來了讯检?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤卫旱,失蹤者是張志新(化名)和其女友劉穎人灼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體顾翼,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡投放,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了暴构。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跪呈。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡段磨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耗绿,到底是詐尸還是另有隱情苹支,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布误阻,位于F島的核電站债蜜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏究反。R本人自食惡果不足惜寻定,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望精耐。 院中可真熱鬧狼速,春花似錦、人聲如沸卦停。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惊完。三九已至僵芹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間小槐,已是汗流浹背拇派。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凿跳,地道東北人件豌。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像拄显,于是被迫代替她去往敵國和親苟径。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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