[譯] 使用強(qiáng)大的 Mockito 來測試你的代碼

這篇教程介紹了如何使用 Mockito 框架來給軟件寫測試用例

1. 預(yù)備知識

如果需要往下學(xué)習(xí)良价,你需要先理解 Junit 框架中的單元測試件豌。

如果你不熟悉 JUnit译打,請查看下面的教程:
http://www.vogella.com/tutorials/JUnit/article.html

2. 使用mock對象來進(jìn)行測試

2.1. 單元測試的目標(biāo)和挑戰(zhàn)

單元測試的思路是在不涉及依賴關(guān)系的情況下測試代碼(隔離性)宵呛,所以測試代碼與其他類或者系統(tǒng)的關(guān)系應(yīng)該盡量被消除。一個可行的消除方法是替換掉依賴類(測試替換)羽氮,也就是說我們可以使用替身來替換掉真正的依賴對象缘回。

2.2. 測試類的分類

dummy object 做為參數(shù)傳遞給方法但是絕對不會被使用。譬如說念脯,這種測試類內(nèi)部的方法不會被調(diào)用,或者是用來填充某個方法的參數(shù)弯淘。

Fake 是真正接口或抽象類的實(shí)現(xiàn)體绿店,但給對象內(nèi)部實(shí)現(xiàn)很簡單。譬如說庐橙,它存在內(nèi)存中而不是真正的數(shù)據(jù)庫中惯吕。(譯者注:Fake 實(shí)現(xiàn)了真正的邏輯惕它,但它的存在只是為了測試,而不適合于用在產(chǎn)品中废登。)

stub 類是依賴類的部分方法實(shí)現(xiàn),而這些方法在你測試類和接口的時候會被用到郁惜,也就是說 stub 類在測試中會被實(shí)例化堡距。stub 類會回應(yīng)任何外部測試的調(diào)用。stub 類有時候還會記錄調(diào)用的一些信息兆蕉。

mock object 是指類或者接口的模擬實(shí)現(xiàn)羽戒,你可以自定義這個對象中某個方法的輸出結(jié)果。

測試替代技術(shù)能夠在測試中模擬測試類以外對象虎韵。因此你可以驗(yàn)證測試類是否響應(yīng)正常易稠。譬如說,你可以驗(yàn)證在 Mock 對象的某一個方法是否被調(diào)用包蓝。這可以確保隔離了外部依賴的干擾只測試測試類驶社。

我們選擇 Mock 對象的原因是因?yàn)?Mock 對象只需要少量代碼的配置。

2.3. Mock 對象的產(chǎn)生

你可以手動創(chuàng)建一個 Mock 對象或者使用 Mock 框架來模擬這些類测萎,Mock 框架允許你在運(yùn)行時創(chuàng)建 Mock 對象并且定義它的行為亡电。

一個典型的例子是把 Mock 對象模擬成數(shù)據(jù)的提供者。在正式的生產(chǎn)環(huán)境中它會被實(shí)現(xiàn)用來連接數(shù)據(jù)源硅瞧。但是我們在測試的時候 Mock 對象將會模擬成數(shù)據(jù)提供者來確保我們的測試環(huán)境始終是相同的份乒。

Mock 對象可以被提供來進(jìn)行測試。因此腕唧,我們測試的類應(yīng)該避免任何外部數(shù)據(jù)的強(qiáng)依賴或辖。

通過 Mock 對象或者 Mock 框架,我們可以測試代碼中期望的行為枣接。譬如說颂暇,驗(yàn)證只有某個存在 Mock 對象的方法是否被調(diào)用了。

2.4. 使用 Mockito 生成 Mock 對象

Mockito 是一個流行 mock 框架月腋,可以和JUnit結(jié)合起來使用蟀架。Mockito 允許你創(chuàng)建和配置 mock 對象。使用Mockito可以明顯的簡化對外部依賴的測試類的開發(fā)榆骚。

一般使用 Mockito 需要執(zhí)行下面三步

  • 模擬并替換測試代碼中外部依賴片拍。

  • 執(zhí)行測試代碼

  • 驗(yàn)證測試代碼是否被正確的執(zhí)行

mockitousagevisualization

3. 為自己的項(xiàng)目添加 Mockito 依賴

3.1. 在 Gradle 添加 Mockito 依賴

如果你的項(xiàng)目使用 Gradle 構(gòu)建,將下面代碼加入 Gradle 的構(gòu)建文件中為自己項(xiàng)目添加 Mockito 依賴

repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:2.0.57-beta" }

3.2. 在 Maven 添加 Mockito 依賴

需要在 Maven 聲明依賴妓肢,您可以在 http://search.maven.org 網(wǎng)站中搜索 g:"org.mockito", a:"mockito-core" 來得到具體的聲明方式捌省。

3.3. 在 Eclipse IDE 使用 Mockito

Eclipse IDE 支持 Gradle 和 Maven 兩種構(gòu)建工具,所以在 Eclipse IDE 添加依賴取決你使用的是哪一個構(gòu)建工具碉钠。

3.4. 以 OSGi 或者 Eclipse 插件形式添加 Mockito 依賴

在 Eclipse RCP 應(yīng)用依賴通掣倩海可以在 p2 update 上得到卷拘。Orbit 是一個很好的第三方倉庫,我們可以在里面尋找能在 Eclipse 上使用的應(yīng)用和插件祝高。

Orbit 倉庫地址 http://download.eclipse.org/tools/orbit/downloads

orbit p2 mockito

4. 使用Mockito API

4.1. 靜態(tài)引用

如果在代碼中靜態(tài)引用了org.mockito.Mockito.*;栗弟,那你你就可以直接調(diào)用靜態(tài)方法和靜態(tài)變量而不用創(chuàng)建對象,譬如直接調(diào)用 mock() 方法工闺。

4.2. 使用 Mockito 創(chuàng)建和配置 mock 對象

除了上面所說的使用 mock() 靜態(tài)方法外乍赫,Mockito 還支持通過 @Mock 注解的方式來創(chuàng)建 mock 對象。

如果你使用注解陆蟆,那么必須要實(shí)例化 mock 對象雷厂。Mockito 在遇到使用注解的字段的時候,會調(diào)用MockitoAnnotations.initMocks(this) 來初始化該 mock 對象叠殷。另外也可以通過使用@RunWith(MockitoJUnitRunner.class)來達(dá)到相同的效果改鲫。

通過下面的例子我們可以了解到使用@Mock 的方法和MockitoRule規(guī)則。

import static org.mockito.Mockito.*;

public class MockitoTest  {

        @Mock
        MyDatabase databaseMock; (1)

        @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); (2)

        @Test
        public void testQuery()  {
                ClassToTest t  = new ClassToTest(databaseMock); (3)
                boolean check = t.query("* from t"); (4)
                assertTrue(check); (5)
                verify(databaseMock).query("* from t"); (6)
        }
}
  1. 告訴 Mockito 模擬 databaseMock 實(shí)例

  2. Mockito 通過 @mock 注解創(chuàng)建 mock 對象

  3. 使用已經(jīng)創(chuàng)建的mock初始化這個類

  4. 在測試環(huán)境下林束,執(zhí)行測試類中的代碼

  5. 使用斷言確保調(diào)用的方法返回值為 true

  6. 驗(yàn)證 query 方法是否被 MyDatabase 的 mock 對象調(diào)用

4.3. 配置 mock

當(dāng)我們需要配置某個方法的返回值的時候像棘,Mockito 提供了鏈?zhǔn)降?API 供我們方便的調(diào)用

when(…?.).thenReturn(…?.)可以被用來定義當(dāng)條件滿足時函數(shù)的返回值,如果你需要定義多個返回值诊县,可以多次定義讲弄。當(dāng)你多次調(diào)用函數(shù)的時候,Mockito 會根據(jù)你定義的先后順序來返回返回值依痊。Mocks 還可以根據(jù)傳入?yún)?shù)的不同來定義不同的返回值避除。譬如說你的函數(shù)可以將anyString 或者 anyInt作為輸入?yún)?shù),然后定義其特定的放回值胸嘁。

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

@Test
public void test1()  {
        //  創(chuàng)建 mock
        MyClass test = Mockito.mock(MyClass.class);

        // 自定義 getUniqueId() 的返回值
        when(test.getUniqueId()).thenReturn(43);

        // 在測試中使用mock對象
        assertEquals(test.getUniqueId(), 43);
}

// 返回多個值
@Test
public void testMoreThanOneReturnValue()  {
        Iterator i= mock(Iterator.class);
        when(i.next()).thenReturn("Mockito").thenReturn("rocks");
        String result=i.next()+" "+i.next();
        // 斷言
        assertEquals("Mockito rocks", result);
}

// 如何根據(jù)輸入來返回值
@Test
public void testReturnValueDependentOnMethodParameter()  {
        Comparable c= mock(Comparable.class);
        when(c.compareTo("Mockito")).thenReturn(1);
        when(c.compareTo("Eclipse")).thenReturn(2);
        // 斷言
        assertEquals(1,c.compareTo("Mockito"));
}

// 如何讓返回值不依賴于輸入
@Test
public void testReturnValueInDependentOnMethodParameter()  {
        Comparable c= mock(Comparable.class);
        when(c.compareTo(anyInt())).thenReturn(-1);
        // 斷言
        assertEquals(-1 ,c.compareTo(9));
}

// 根據(jù)參數(shù)類型來返回值
@Test
public void testReturnValueInDependentOnMethodParameter()  {
        Comparable c= mock(Comparable.class);
        when(c.compareTo(isA(Todo.class))).thenReturn(0);
        // 斷言
        Todo todo = new Todo(5);
        assertEquals(todo ,c.compareTo(new Todo(1)));
}

對于無返回值的函數(shù)瓶摆,我們可以使用doReturn(…?).when(…?).methodCall來獲得類似的效果。例如我們想在調(diào)用某些無返回值函數(shù)的時候拋出異常性宏,那么可以使用doThrow 方法群井。如下面代碼片段所示

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

// 下面測試用例描述了如何使用doThrow()方法

@Test(expected=IOException.class)
public void testForIOException() {
        // 創(chuàng)建并配置 mock 對象
        OutputStream mockStream = mock(OutputStream.class);
        doThrow(new IOException()).when(mockStream).close();

        // 使用 mock
        OutputStreamWriter streamWriter= new OutputStreamWriter(mockStream);
        streamWriter.close();
}

4.4. 驗(yàn)證 mock 對象方法是否被調(diào)用

Mockito 會跟蹤 mock 對象里面所有的方法和變量。所以我們可以用來驗(yàn)證函數(shù)在傳入特定參數(shù)的時候是否被調(diào)用毫胜。這種方式的測試稱行為測試书斜,行為測試并不會檢查函數(shù)的返回值,而是檢查在傳入正確參數(shù)時候函數(shù)是否被調(diào)用酵使。

import static org.mockito.Mockito.*;

@Test
public void testVerify()  {
        // 創(chuàng)建并配置 mock 對象
        MyClass test = Mockito.mock(MyClass.class);
        when(test.getUniqueId()).thenReturn(43);

        // 調(diào)用mock對象里面的方法并傳入?yún)?shù)為12
        test.testing(12);
        test.getUniqueId();
        test.getUniqueId();

        // 查看在傳入?yún)?shù)為12的時候方法是否被調(diào)用
        verify(test).testing(Matchers.eq(12));

        // 方法是否被調(diào)用兩次
        verify(test, times(2)).getUniqueId();

        // 其他用來驗(yàn)證函數(shù)是否被調(diào)用的方法
        verify(mock, never()).someMethod("never called");
        verify(mock, atLeastOnce()).someMethod("called at least once");
        verify(mock, atLeast(2)).someMethod("called at least twice");
        verify(mock, times(5)).someMethod("called five times");
        verify(mock, atMost(3)).someMethod("called at most 3 times");
}

4.5. 使用 Spy 封裝 java 對象

@Spy或者spy()方法可以被用來封裝 java 對象荐吉。被封裝后,除非特殊聲明(打樁 stub)口渔,否則都會真正的調(diào)用對象里面的每一個方法

import static org.mockito.Mockito.*;

// Lets mock a LinkedList
List list = new LinkedList();
List spy = spy(list);

// 可用 doReturn() 來打樁
doReturn("foo").when(spy).get(0);

// 下面代碼不生效
// 真正的方法會被調(diào)用
// 將會拋出 IndexOutOfBoundsException 的異常样屠,因?yàn)?List 為空
when(spy.get(0)).thenReturn("foo");

方法verifyNoMoreInteractions()允許你檢查沒有其他的方法被調(diào)用了。

4.6. 使用 @InjectMocks 在 Mockito 中進(jìn)行依賴注入

我們也可以使用@InjectMocks 注解來創(chuàng)建對象,它會根據(jù)類型來注入對象里面的成員方法和變量痪欲。假定我們有 ArticleManager 類

public class ArticleManager {
    private User user;
    private ArticleDatabase database;

    ArticleManager(User user) {
     this.user = user;
    }

    void setDatabase(ArticleDatabase database) { }
}

這個類會被 Mockito 構(gòu)造悦穿,而類的成員方法和變量都會被 mock 對象所代替,正如下面的代碼片段所示:

@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest  {

       @Mock ArticleCalculator calculator;
       @Mock ArticleDatabase database;
       @Most User user;

       @Spy private UserProvider userProvider = new ConsumerUserProvider();

       @InjectMocks private ArticleManager manager; (1)

       @Test public void shouldDoSomething() {
               // 假定 ArticleManager 有一個叫 initialize() 的方法被調(diào)用了
               // 使用 ArticleListener 來調(diào)用 addListener 方法
               manager.initialize();

               // 驗(yàn)證 addListener 方法被調(diào)用
               verify(database).addListener(any(ArticleListener.class));
       }
}
  1. 創(chuàng)建ArticleManager實(shí)例并注入Mock對象

更多的詳情可以查看
http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/InjectMocks.html.

4.7. 捕捉參數(shù)

ArgumentCaptor類允許我們在verification期間訪問方法的參數(shù)业踢。得到方法的參數(shù)后我們可以使用它進(jìn)行測試栗柒。

import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import java.util.Arrays;
import java.util.List;

import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

public class MockitoTests {

        @Rule public MockitoRule rule = MockitoJUnit.rule();

        @Captor
    private ArgumentCaptor> captor;

        @Test
    public final void shouldContainCertainListItem() {
        List asList = Arrays.asList("someElement_test", "someElement");
        final List mockedList = mock(List.class);
        mockedList.addAll(asList);

        verify(mockedList).addAll(captor.capture());
        final List capturedArgument = captor.>getValue();
        assertThat(capturedArgument, hasItem("someElement"));
    }
}

4.8. Mockito的限制

Mockito當(dāng)然也有一定的限制。而下面三種數(shù)據(jù)類型則不能夠被測試

  • final classes

  • anonymous classes

  • primitive types

5. 在Android中使用Mockito

在 Android 中的 Gradle 構(gòu)建文件中加入 Mockito 依賴后就可以直接使用 Mockito 了陨亡。若想使用 Android Instrumented tests 的話傍衡,還需要添加 dexmaker 和 dexmaker-mockito 依賴到 Gradle 的構(gòu)建文件中。(需要 Mockito 1.9.5版本以上)

dependencies {
    testCompile 'junit:junit:4.12'
    // Mockito unit test 的依賴
    testCompile 'org.mockito:mockito-core:1.+'
    // Mockito Android instrumentation tests 的依賴
    androidTestCompile 'org.mockito:mockito-core:1.+'
    androidTestCompile "com.google.dexmaker:dexmaker:1.2"
    androidTestCompile "com.google.dexmaker:dexmaker-mockito:1.2"
}

6. 實(shí)例:使用Mockito寫一個Instrumented Unit Test

6.1. 創(chuàng)建一個測試的Android 應(yīng)用

創(chuàng)建一個包名為com.vogella.android.testing.mockito.contextmock的Android應(yīng)用负蠕,添加一個靜態(tài)方法
,方法里面創(chuàng)建一個包含參數(shù)的Intent倦畅,如下代碼所示:

public static Intent createQuery(Context context, String query, String value) {
    // 簡單起見遮糖,重用MainActivity
    Intent i = new Intent(context, MainActivity.class);
    i.putExtra("QUERY", query);
    i.putExtra("VALUE", value);
    return i;
}

6.2. 在app/build.gradle文件中添加Mockito依賴

dependencies {
    // Mockito 和 JUnit 的依賴
    // instrumentation unit tests on the JVM
    androidTestCompile 'junit:junit:4.12'
    androidTestCompile 'org.mockito:mockito-core:2.0.57-beta'
    androidTestCompile 'com.android.support.test:runner:0.3'
    androidTestCompile "com.google.dexmaker:dexmaker:1.2"
    androidTestCompile "com.google.dexmaker:dexmaker-mockito:1.2"

    // Mockito 和 JUnit 的依賴
    // tests on the JVM
    testCompile 'junit:junit:4.12'
    testCompile 'org.mockito:mockito-core:1.+'

}

6.3. 創(chuàng)建測試

使用 Mockito 創(chuàng)建一個單元測試來驗(yàn)證在傳遞正確 extra data 的情況下,intent 是否被觸發(fā)叠赐。

因此我們需要使用 Mockito 來 mock 一個Context對象欲账,如下代碼所示:

package com.vogella.android.testing.mockitocontextmock;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class TextIntentCreation {

    @Test
    public void testIntentShouldBeCreated() {
        Context context = Mockito.mock(Context.class);
        Intent intent = MainActivity.createQuery(context, "query", "value");
        assertNotNull(intent);
        Bundle extras = intent.getExtras();
        assertNotNull(extras);
        assertEquals("query", extras.getString("QUERY"));
        assertEquals("value", extras.getString("VALUE"));
    }
}

7. 實(shí)例:使用 Mockito 創(chuàng)建一個 mock 對象

7.1. 目標(biāo)

創(chuàng)建一個 Api,它可以被 Mockito 來模擬并做一些工作

7.2. 創(chuàng)建一個Twitter API 的例子

實(shí)現(xiàn) TwitterClient類芭概,它內(nèi)部使用到了 ITweet 的實(shí)現(xiàn)赛不。但是ITweet實(shí)例很難得到,譬如說他需要啟動一個很復(fù)雜的服務(wù)來得到罢洲。

public interface ITweet {

        String getMessage();
}


public class TwitterClient {

        public void sendTweet(ITweet tweet) {
                String message = tweet.getMessage();

                // send the message to Twitter
        }
}

7.3. 模擬 ITweet 的實(shí)例

為了能夠不啟動復(fù)雜的服務(wù)來得到 ITweet踢故,我們可以使用 Mockito 來模擬得到該實(shí)例。

@Test
public void testSendingTweet() {
        TwitterClient twitterClient = new TwitterClient();

        ITweet iTweet = mock(ITweet.class);

        when(iTweet.getMessage()).thenReturn("Using mockito is great");

        twitterClient.sendTweet(iTweet);
}

現(xiàn)在 TwitterClient 可以使用 ITweet 接口的實(shí)現(xiàn)惹苗,當(dāng)調(diào)用 getMessage() 方法的時候?qū)蛴?"Using Mockito is great" 信息殿较。

7.4. 驗(yàn)證方法調(diào)用

確保 getMessage() 方法至少調(diào)用一次。

@Test
public void testSendingTweet() {
        TwitterClient twitterClient = new TwitterClient();

        ITweet iTweet = mock(ITweet.class);

        when(iTweet.getMessage()).thenReturn("Using mockito is great");

        twitterClient.sendTweet(iTweet);

        verify(iTweet, atLeastOnce()).getMessage();
}

7.5. 驗(yàn)證

運(yùn)行測試桩蓉,查看代碼是否測試通過淋纲。

8. 模擬靜態(tài)方法

8.1. 使用 Powermock 來模擬靜態(tài)方法

因?yàn)?Mockito 不能夠 mock 靜態(tài)方法,因此我們可以使用 Powermock院究。

import java.net.InetAddress;
import java.net.UnknownHostException;

public final class NetworkReader {
    public static String getLocalHostname() {
        String hostname = "";
        try {
            InetAddress addr = InetAddress.getLocalHost();
            // Get hostname
            hostname = addr.getHostName();
        } catch ( UnknownHostException e ) {
        }
        return hostname;
    }
}

我們模擬了 NetworkReader 的依賴洽瞬,如下代碼所示:

import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;

@RunWith( PowerMockRunner.class )
@PrepareForTest( NetworkReader.class )
public class MyTest {

// 測試代碼

 @Test
public void testSomething() {
    mockStatic( NetworkUtil.class );
    when( NetworkReader.getLocalHostname() ).andReturn( "localhost" );

    // 與 NetworkReader 協(xié)作的測試
}

8.2.用封裝的方法代替Powermock

有時候我們可以在靜態(tài)方法周圍包含非靜態(tài)的方法來達(dá)到和 Powermock 同樣的效果。

class FooWraper { 
      void someMethod() { 
           Foo.someStaticMethod() 
       } 
}

9. Mockito 參考資料

http://site.mockito.org - Mockito 官網(wǎng)

https://github.com/mockito/mockito- Mockito Github

https://github.com/mockito/mockito/blob/master/doc/release-notes/official.md - Mockito 發(fā)行說明

http://martinfowler.com/articles/mocksArentStubs.html 與Mocks业汰,Stub有關(guān)的文章

http://chiuki.github.io/advanced-android-espresso/ 高級android教程(竟然是個妹子)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伙窃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蔬胯,更是在濱河造成了極大的恐慌对供,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異产场,居然都是意外死亡鹅髓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門京景,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窿冯,“玉大人,你說我怎么就攤上這事确徙⌒汛” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵鄙皇,是天一觀的道長芜赌。 經(jīng)常有香客問我,道長伴逸,這世上最難降的妖魔是什么缠沈? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮错蝴,結(jié)果婚禮上洲愤,老公的妹妹穿的比我還像新娘。我一直安慰自己顷锰,他們只是感情好柬赐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著官紫,像睡著了一般肛宋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上万矾,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天悼吱,我揣著相機(jī)與錄音,去河邊找鬼良狈。 笑死后添,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的薪丁。 我是一名探鬼主播遇西,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼严嗜!你這毒婦竟也來了粱檀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤漫玄,失蹤者是張志新(化名)和其女友劉穎茄蚯,沒想到半個月后压彭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渗常,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年壮不,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片皱碘。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡询一,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出癌椿,到底是詐尸還是另有隱情健蕊,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布踢俄,位于F島的核電站缩功,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏都办。R本人自食惡果不足惜掂之,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脆丁。 院中可真熱鬧,春花似錦动雹、人聲如沸槽卫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歼培。三九已至,卻和暖如春茸塞,著一層夾襖步出監(jiān)牢的瞬間躲庄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工钾虐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留噪窘,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓效扫,卻偏偏與公主長得像倔监,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子菌仁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理浩习,服務(wù)發(fā)現(xiàn),斷路器济丘,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • 幾點(diǎn)說明:代碼中的 //<== 表示跟上面的相比谱秽,這是新增的,或者是修改的代碼,不知道怎么樣在代碼塊里面再強(qiáng)調(diào)幾行...
    鄒小創(chuàng)閱讀 13,969評論 15 41
  • 一疟赊、百變怪 Mockito Mockito可謂是Java世界的百變怪郊供,使用它,可以輕易的復(fù)制出各種類型的對象听绳,并與...
    羅力閱讀 3,900評論 3 18
  • Instrumentation介紹 Instrumentation是個什么東西颂碘? Instrumentation測...
    打不死的小強(qiáng)qz閱讀 7,755評論 2 39
  • 春桃一天要吃兩碗飯。一碗是凈米椅挣,白絲絲的看著好看头岔,一碗是拌了醬油的,黃澄澄的聞著誘人鼠证。 吃飯很重要峡竣,尤其是對春桃這...
    林帥閱讀 1,091評論 0 1