Android單元測試-常見的方案比較

前言

本文將介紹在Android Studio中,android單元測試的介紹和實(shí)現(xiàn)。相關(guān)代碼托管在github上的AndroidJunitDemo中凛驮,涉及到的用例代碼收集于google官方提供的測試用例android-testing棒假,同時(shí)進(jìn)行了簡化和修改。你可以從該demo中學(xué)習(xí)單元測試簡單的使用烂瘫,在工程中媒熊,包含兩個(gè)模塊,一個(gè)實(shí)現(xiàn)計(jì)算器功能的CalculationActivity坟比,另外一個(gè)是PersonlInfoActivity芦鳍,可以編輯姓名,郵箱和生日等信息葛账,并保存到SharePreferences中柠衅,同時(shí)提供了兩個(gè)模塊的單元測試。

單元測試

關(guān)于單元測試籍琳,在維基百科中茄茁,給出了如下定義:

在計(jì)算機(jī)編程中,單元測試(英語:Unit Testing)又稱為模塊測試, 是針對(duì)程序模塊(軟件設(shè)計(jì)的最小單位)來進(jìn)行正確性檢驗(yàn)的測試工作巩割。程序單元是應(yīng)用的最小可測試部件裙顽。在過程化編程中,一個(gè)單元就是單個(gè)程序宣谈、函數(shù)愈犹、過程等;對(duì)于面向?qū)ο缶幊蹋钚卧褪欠椒ㄤ鲈酰ɑ悾ǔ悾┭薄⒊橄箢悺⒒蛘吲缮悾ㄗ宇悾┲械姆椒ā?/p>

android中的單元測試基于JUnit勋锤,可分為本地測試和instrumented測試饭玲,在項(xiàng)目中對(duì)應(yīng)

  • module-name/src/test/java/.
      該目錄下的代碼運(yùn)行在本地JVM上,其優(yōu)點(diǎn)是速度快叁执,不需要設(shè)備或模擬器的支持茄厘,但是無法直接運(yùn)行含有android系統(tǒng)API引用的測試代碼。
  • module-name/src/androidTest/java/.
      該目錄下的測試代碼需要運(yùn)行在android設(shè)備或模擬器下面谈宛,因此可以使用android系統(tǒng)的API次哈,速度較慢。
      
    目錄

以上分別執(zhí)行在JUnit和AndroidJUnitRunner的測試運(yùn)行環(huán)境吆录,兩者主要的區(qū)別在于是否需要android系統(tǒng)API的依賴窑滞。
  在實(shí)際開發(fā)過程中,我們應(yīng)該盡量用JUnit實(shí)現(xiàn)本地JVM的單元測試恢筝,而項(xiàng)目中的代碼大致可分為以下三類:

  • 1.強(qiáng)依賴關(guān)系哀卫,如在Activity,Service等組件中的方法撬槽,其特點(diǎn)是大部分為private方法此改,并且與其生命周期相關(guān),無法直接進(jìn)行單元測試恢氯,可以進(jìn)行Ecspreso等UI測試带斑。
  • 2.部分依賴,代碼實(shí)現(xiàn)依賴注入勋拟,該類需要依賴Context等android對(duì)象的依賴勋磕,可以通過Mock或其它第三方框架實(shí)現(xiàn)JUnit單元測試或使用androidJunitRunner進(jìn)行單元測試。
  • 3.純java代碼敢靡,不存在對(duì)android庫的依賴挂滓,可以進(jìn)行JUnit單元測試

常用的測試框架

在android測試框架中,常用的有以下幾個(gè)框架和工具類:

  • JUnit4
  • AndroidJUnitRunner
  • Mockito
  • Espresso

關(guān)于單元測試框架的選擇啸胧,可以參考下圖:

android單元測試

JUnit4

JUnit4是一套基于注解的單元測試框架赶站。在android studio中,編寫在test目錄下的測試類都是基于該框架實(shí)現(xiàn)纺念,該目錄下的測試代碼運(yùn)行在本地的JVM上贝椿,不需要設(shè)備(真機(jī)或模擬器)的支持。
  JUnit4中常用的幾個(gè)注解:

  • @BeforeClass 測試類里所有用例運(yùn)行之前陷谱,運(yùn)行一次這個(gè)方法烙博。方法必須是public static void
  • @AfterClass 與BeforeClass對(duì)應(yīng)
  • @Before 在每個(gè)用測試?yán)\(yùn)行之前都運(yùn)行一次瑟蜈。
  • @After 與Before對(duì)應(yīng)
  • @Test 指定該方法為測試方法,方法必須是public void
  • @RunWith 測試類名之前渣窜,用來確定這個(gè)類的測試運(yùn)行器

對(duì)于其它的注解铺根,可以通過查看junit4官網(wǎng)來進(jìn)一步學(xué)習(xí)。
  在test下添加測試類乔宿,對(duì)于需要進(jìn)行測試的方法添加@Test注解位迂,在該方法中使用assert進(jìn)行判斷,為了使assert更加直觀详瑞,方便掂林,可以使用Hamcrest library,通過使用hamcrest的匹配工具蛤虐,可以讓你更靈活的進(jìn)行測試党饮。 以下是一個(gè)最簡單的測試類CalculatorTest的實(shí)現(xiàn):

public class CalculatorTest {

    /** 計(jì)算功能類 */
    private Calculator mCalculator;

    @Before
    public void setUp() {
        mCalculator = new Calculator();
    }

    /**
     * 方法的命名盡量描述詳細(xì)
     * 測試兩個(gè)數(shù)相加
     */
    @Test
    public void addTwoNumbers() {
        double resultAdd = mCalculator.add(1d, 1d);
        //使用hamcrest進(jìn)行assert肝陪,直觀驳庭,易讀
        assertThat(resultAdd, is(equalTo(2d)));
    }
    ……
}

當(dāng)需要傳入多個(gè)參數(shù)進(jìn)行條件,即條件覆蓋時(shí)氯窍,可以使用@Parameters來進(jìn)行單個(gè)方法的多次不同參數(shù)的測試饲常,對(duì)應(yīng)Demo中的CalculatorWithParameterizedTest測試類,使用該方法需要如下步驟:

  • 1.在測試類上添加@RunWith(Parameterized.class)注解狼讨。
  • 2.添加構(gòu)造方法贝淤,并將測試的參數(shù)作為其構(gòu)造參數(shù)。
  • 3.添加獲取參數(shù)集合的static方法政供,并在該方法上添加@Parameters注解播聪。
  • 4.在需要測試的方法中直接使用成員變量,該變量由JUnit通過構(gòu)造方法生成布隔。
@RunWith(Parameterized.class)
public class CalculatorWithParameterizedTest {

    /** 參數(shù)的變量 */
    private final double mOperandOne;
    private final double mOperandTwo;
    /** 期待值 */
    private final double mExpectedResult;
    /** 計(jì)算類 */
    private Calculator mCalculator;

    /**
     * 構(gòu)造方法离陶,框架可以自動(dòng)填充參數(shù)
     */
    public CalculatorWithParameterizedTest(double operandOne, double operandTwo,
            double expectedResult){
        mOperandOne = operandOne;
        mOperandTwo = operandTwo;
        mExpectedResult = expectedResult;
    }

    /**
     * 需要測試的參數(shù)和對(duì)應(yīng)結(jié)果
     */
    @Parameterized.Parameters
    public static Collection<Object[]> initData(){
        return Arrays.asList(new Object[][]{
                {0, 0, 0},
                {0, -1, -1},
                {2, 2, 4},
                {8, 8, 16},
                {16, 16, 32},
                {32, 0, 32},
                {64, 64, 128}});
    }


    @Before
    public void setUp() {
        mCalculator = new Calculator();
    }

    /**
     * 使用參數(shù)組測試加的相關(guān)操作
     */
    @Test
    public void testAdd_TwoNumbers() {
        double resultAdd = mCalculator.add(mOperandOne, mOperandTwo);
        assertThat(resultAdd, is(equalTo(mExpectedResult)));
    }

}

現(xiàn)在目錄下存在如下兩個(gè)Test類:

多個(gè)測試類

如果我們需要同時(shí)運(yùn)行兩個(gè)或多個(gè)Test類怎么辦?JUnit提供了Suite注解衅檀,在對(duì)應(yīng)的測試目錄下創(chuàng)建一個(gè)空Test類招刨,如Demo里的UnitTestSuite,該類上添加如下注解:

  • @RunWith(Suite.class):配置Runner運(yùn)行環(huán)境哀军。
  • @Suite.SuiteClasses({A.class, B.class}):添加需要一起運(yùn)行的測試類沉眶。
    @RunWith(Suite.class)
    @Suite.SuiteClasses({CalculatorTest.class, CalculatorWithParameterizedTest.class})
    public class UnitTestSuite {
    }

目前為止已經(jīng)可以完成簡單的單元測試了,但在android中杉适,方法中使用到android系統(tǒng)api是一件司空見慣的事谎倔,比如Context,Parcelable猿推,SharedPreferences等等片习。而在本地JVM中無法調(diào)用這些接口,因此,我們就需要使用AndroidJUnitRunner來完成這些方法的測試

AndroidJUnitRunner

當(dāng)單元測試中涉及到大量的android系統(tǒng)庫的調(diào)用時(shí)毯侦,你可以通過該方案類完成測試哭靖。使用方法是在androidTest目錄下創(chuàng)建測試類,在該類上添加@RunWith(AndroidJUnit4.class)注解侈离。
  在Demo中androidTest目錄下的SharedPreferencesHelperTest測試類试幽,該類對(duì)SharedPreferencesHelper進(jìn)行了單元測試,其方法內(nèi)部涉及到了SharedPreferences卦碾,該類屬于android系統(tǒng)的api铺坞,因此無法直接在test中運(yùn)行。部分實(shí)現(xiàn)代碼如下:

@RunWith(AndroidJUnit4.class)
public class SharedPreferencesHelperTest {

    private static final String TEST_NAME = "Test name";

    private static final String TEST_EMAIL = "test@email.com";

    private static final Calendar TEST_DATE_OF_BIRTH = Calendar.getInstance();

    private SharedPreferenceEntry mSharedPreferenceEntry;

    private SharedPreferencesHelper mSharedPreferencesHelper;

    private SharedPreferences mSharePreferences;

    /** 上下文 */
    private Context mContext;
    ……
    @Before
    public void setUp() throws Exception {
        //獲取application的context
        mContext = InstrumentationRegistry.getTargetContext();
        //實(shí)例化SharedPreferences
        mSharePreferences = PreferenceManager.getDefaultSharedPreferences(mContext);

        mSharedPreferenceEntry = new SharedPreferenceEntry(TEST_NAME, TEST_DATE_OF_BIRTH, TEST_EMAIL);
        //實(shí)例化SharedPreferencesHelper洲胖,依賴注入SharePreferences
        mSharedPreferencesHelper = new SharedPreferencesHelper(mSharePreferences);

        //以下是在mock的相關(guān)操作济榨,模擬commit失敗
        mMockSharePreferences = Mockito.mock(SharedPreferences.class);
        mMockBrokenEditor = Mockito.mock(SharedPreferences.Editor.class);
        when(mMockSharePreferences.edit()).thenReturn(mMockBrokenEditor);
        when(mMockBrokenEditor.commit()).thenReturn(false);
        mMockSharedPreferencesHelper = new SharedPreferencesHelper(mMockSharePreferences);
    }

    /**
     * 測試保存數(shù)據(jù)是否成功
     */
    @Test
    public void sharedPreferencesHelper_SavePersonalInformation() throws Exception {
        assertThat(mSharedPreferencesHelper.savePersonalInfo(mSharedPreferenceEntry), is(true));
    }
    /**
     * 測試保存數(shù)據(jù),然后獲取數(shù)據(jù)是否成功
     */
    @Test
    public void sharedPreferencesHelper_SaveAndReadPersonalInformation() throws Exception {
        mSharedPreferencesHelper.savePersonalInfo(mSharedPreferenceEntry);
        SharedPreferenceEntry sharedPreferenceEntry = mSharedPreferencesHelper.getPersonalInfo();
        assertThat(isEquals(mSharedPreferenceEntry, sharedPreferenceEntry), is(true));
    }
    ……
}

在AndroidJUnitRunner中绿映,通過InstrumentationRegistry來獲取Context擒滑,并實(shí)例化SharedPreferences,然后通過依賴注入來完成SharedPreferencesHelper對(duì)象的生成叉弦。對(duì)于AndroidJUnitRunner更詳細(xì)的介紹丐一,可以參考android官方文檔測試支持庫
  使用AndroidJUnitRunner最大的缺點(diǎn)在于無法在本地JVM運(yùn)行淹冰,直接的結(jié)果就是測試速度慢库车,同時(shí)無法執(zhí)行覆蓋測試。因此出現(xiàn)了很多替代方案樱拴,比如在設(shè)計(jì)合理柠衍,依賴注入實(shí)現(xiàn)的代碼,可以使用Mockito來進(jìn)行本地測試晶乔,或者使用第三方測試框架Robolectric等珍坊。

Mockito

涉及到android依賴的方法的測試,除了在androidTest使用瘪弓,還可以通過mock來執(zhí)行本地測試垫蛆。使用Mock的目的主要有以下兩點(diǎn):

  • 驗(yàn)證這個(gè)對(duì)象的某些方法的調(diào)用情況,調(diào)用了多少次腺怯,參數(shù)是什么等等
  • 指定這個(gè)對(duì)象的某些方法的行為袱饭,返回特定的值,或者是執(zhí)行特定的動(dòng)作

Mockito是優(yōu)秀的mock框架之一呛占,使用該框架可以使mock的操作更加簡單虑乖,直觀。
  要使用Mockito晾虑,需要添加如下依賴:

    dependencies {
        testCompile 'junit:junit:4.12'
        // 如果要使用Mockito疹味,你需要添加此條依賴庫
        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"
    }

AndroidJUnitRunner介紹中的對(duì)于SharedPreferencesHelper的測試,由于其依賴注入的設(shè)計(jì)糙捺,我們可以方便的去mock一個(gè)SharePreferences來執(zhí)行本地的測試诫咱。在Demo中的test目錄下的SharedPreferencesHelperWithMockTest類即通過mockito來完成測試的,主要代碼如下:

@RunWith(MockitoJUnitRunner.class)
public class SharedPreferencesHelperWithMockTest {

    private static final String TEST_NAME = "Test name";
    private static final String TEST_EMAIL = "test@email.com";
    private static final Calendar TEST_DATE_OF_BIRTH = Calendar.getInstance();
    private SharedPreferencesHelper mSharedPreferencesHelper;
    private SharedPreferenceEntry mSharedPreferenceEntry;
    ……
    @Mock
    SharedPreferences mMockSharedPreferences;
    @Mock
    SharedPreferences.Editor mMockEditor;
    ……
    @Before
    public void setUp() throws Exception {
        mSharedPreferenceEntry = new SharedPreferenceEntry(TEST_NAME, TEST_DATE_OF_BIRTH, TEST_EMAIL);
        mSharedPreferencesHelper = new SharedPreferencesHelper(mockSharePreferences());
        ……
    }

    @Test
    public void sharedPreferencesHelper_SavePersonalInformation() throws Exception {
        assertThat(mSharedPreferencesHelper.savePersonalInfo(mSharedPreferenceEntry), is(true));
    }

    @Test
    public void sharedPreferencesHelper_SaveAndReadPersonalInformation() throws Exception {
        mSharedPreferencesHelper.savePersonalInfo(mSharedPreferenceEntry);
        SharedPreferenceEntry sharedPreferenceEntry = mSharedPreferencesHelper.getPersonalInfo();
        assertThat(isEquals(mSharedPreferenceEntry, sharedPreferenceEntry), is(true));
    }
    ……
    /**
     * 編寫Mock相關(guān)代碼洪灯,代碼中mock了SharedPreferences類的getXxx的相關(guān)操作坎缭,
     * 均返回SharedPreferenceEntry對(duì)象的值,同時(shí)在代碼中使用到了commit和edit签钩,都需要在方法中進(jìn)行mock實(shí)現(xiàn)
     * Creates a mocked SharedPreferences.
     */
    private SharedPreferences mockSharePreferences(){
        when(mMockSharedPreferences.getString(eq(SharedPreferencesHelper.KEY_NAME), anyString()))
                .thenReturn(mSharedPreferenceEntry.getName());
        when(mMockSharedPreferences.getString(eq(SharedPreferencesHelper.KEY_EMAIL), anyString()))
                .thenReturn(mSharedPreferenceEntry.getEmail());
        when(mMockSharedPreferences.getLong(eq(SharedPreferencesHelper.KEY_DOB), anyLong()))
                .thenReturn(mSharedPreferenceEntry.getDateOfBirth().getTimeInMillis());
        when(mMockEditor.commit()).thenReturn(true);
        when(mMockSharedPreferences.edit()).thenReturn(mMockEditor);
        return mMockSharedPreferences;
    }
    ……
}

Espresso

在Demo中掏呼,除了單元測試的用例,還提供了一個(gè)CalculatorInstrumentationTest測試類铅檩,該類使用Espresso憎夷,一個(gè)官方提供了UI測試框架。注意昧旨,UI測試不屬于單元測試的范疇拾给。通過Espresso的使用,可以編寫簡潔臼予、運(yùn)行可靠的自動(dòng)化UI測試鸣戴。詳細(xì)的使用可以參考測試支持庫中關(guān)于Espresso的使用介紹啃沪。

@RunWith(AndroidJUnit4.class)
@LargeTest
public class CalculatorInstrumentationTest {

    /**
     * 在測試中運(yùn)行Activity
     * A JUnit {@link Rule @Rule} to launch your activity under test. This is a replacement
     * for {@link ActivityInstrumentationTestCase2}.
     * <p>
     * Rules are interceptors which are executed for each test method and will run before
     * any of your setup code in the {@link Before @Before} method.
     * <p>
     * {@link ActivityTestRule} will create and launch of the activity for you and also expose
     * the activity under test. To get a reference to the activity you can use
     * the {@link ActivityTestRule#getActivity()} method.
     */
    @Rule
    public ActivityTestRule<CalculatorActivity> mActivityRule = new ActivityTestRule<>(
            CalculatorActivity.class);
    ……
    private void performOperation(int btnOperationResId, String operandOne,
            String operandTwo, String expectedResult) {
        // 指定輸入框中輸入文本粘拾,同時(shí)關(guān)閉鍵盤
        onView(withId(R.id.operand_one_edit_text)).perform(typeText(operandOne),
                closeSoftKeyboard());
        onView(withId(R.id.operand_two_edit_text)).perform(typeText(operandTwo),
                closeSoftKeyboard());

        // 獲取特定按鈕執(zhí)行點(diǎn)擊事件
        onView(withId(btnOperationResId)).perform(click());

        // 獲取文本框中顯示的結(jié)果
        onView(withId(R.id.operation_result_text_view)).check(matches(withText(expectedResult)));
    }

}

你可以運(yùn)行CalculatorInstrumentationTest測試類,會(huì)有一個(gè)直觀的認(rèn)識(shí)创千。

運(yùn)行單元測試

在Android Studio中缰雇,可以通過以下兩種方式運(yùn)行單元測試:

  • 手動(dòng)運(yùn)行
  • 通過指令運(yùn)行

1.手動(dòng)運(yùn)行

在Android Studio中,對(duì)指定的測試類右鍵追驴,選擇對(duì)應(yīng)的RUN或DEBUG操作選項(xiàng)即可運(yùn)行械哟,如下圖:

運(yùn)行選項(xiàng)

圖中第三個(gè)為覆蓋測試,即運(yùn)行所有的test下的單元測試殿雪,并顯示單元測試的覆蓋率暇咆。如果需要保存測試結(jié)果,可以在結(jié)果框中點(diǎn)擊Export Test Results按鈕:

運(yùn)行選項(xiàng)

結(jié)果會(huì)被保存到項(xiàng)目的目錄下丙曙,可以通過瀏覽器打開查看:

運(yùn)行選項(xiàng)

2.指令運(yùn)行

在Terminal輸入gradle testDebugUnitTestgradle testReleaseUnitTest指令來分別運(yùn)行debug和release版本的unit testing爸业,在執(zhí)行的結(jié)果可以在xxx\project\app\build\reports\tests\testReleaseUnitTest中查看:

運(yùn)行選項(xiàng)

其它

關(guān)于異步操作的單元測試

在實(shí)際的android開發(fā)過程中,經(jīng)常涉及到異步操作亏镰,比如網(wǎng)絡(luò)請(qǐng)求扯旷,Rxjava的線程調(diào)度等。在單元測試中索抓,往往測試方法執(zhí)行往了钧忽,異步操作還沒介紹毯炮,這就導(dǎo)致了無法順利的執(zhí)行單元測試操作。其解決方法可以提供CountDownLatch類來阻塞測試方法的線程耸黑,當(dāng)異步操作完成后(通過回調(diào))來喚醒繼續(xù)執(zhí)行測試桃煎,獲取結(jié)果。其實(shí)對(duì)于網(wǎng)絡(luò)請(qǐng)求這種操作應(yīng)該使用Mock來替代大刊,因?yàn)槟愕膯卧獪y試的結(jié)果不應(yīng)受網(wǎng)絡(luò)的影響备禀,不需要關(guān)注網(wǎng)絡(luò)是否正常,服務(wù)器是否崩潰奈揍,而應(yīng)該把關(guān)注點(diǎn)放在單元本身的操作曲尸。

單元測試,集成測試男翰,UI測試

  • UI測試是測試到交互和視覺俊马,以及操作的結(jié)果是否符合預(yù)期〈兴可以通過Espresso撞反,UI Automator等框架,或者人工測試租冠。
  • 集成測試是基于單元測試鹏倘,將多個(gè)單元測試組裝起來進(jìn)行測試,實(shí)際測試往往會(huì)運(yùn)行慢顽爹,依賴過多導(dǎo)致集成測試非常費(fèi)時(shí)纤泵。
  • 單元測試僅針對(duì)最小單元,在面向?qū)ο笾芯翟粒瑔卧傅氖欠椒筇猓ɑ悾ǔ悾⒊橄箢惾饪省⒒蛘吲缮悾ㄗ宇悾┲械姆椒ā?/li>

三者的在實(shí)際應(yīng)用中可以通過Test Pyramid(Martin Fowler的總結(jié))來衡量:

Test Pyramid

所以對(duì)于測試公荧,在開放過程中,我們(開發(fā)者)需要把更多的精力放在單元測試上同规。

擴(kuò)展閱讀

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市朱灿,隨后出現(xiàn)的幾起案子昧识,更是在濱河造成了極大的恐慌,老刑警劉巖盗扒,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跪楞,死亡現(xiàn)場離奇詭異缀去,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)甸祭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門缕碎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人池户,你說我怎么就攤上這事咏雌。” “怎么了校焦?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵赊抖,是天一觀的道長。 經(jīng)常有香客問我寨典,道長氛雪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任耸成,我火速辦了婚禮报亩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘井氢。我一直安慰自己弦追,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布花竞。 她就那樣靜靜地躺著劲件,像睡著了一般。 火紅的嫁衣襯著肌膚如雪左胞。 梳的紋絲不亂的頭發(fā)上寇仓,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音烤宙,去河邊找鬼。 笑死俭嘁,一個(gè)胖子當(dāng)著我的面吹牛躺枕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播供填,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拐云,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了近她?” 一聲冷哼從身側(cè)響起叉瘩,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎粘捎,沒想到半個(gè)月后薇缅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體危彩,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年泳桦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了汤徽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡灸撰,死狀恐怖谒府,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浮毯,我是刑警寧澤完疫,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站债蓝,受9級(jí)特大地震影響趋惨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜惦蚊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一器虾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蹦锋,春花似錦兆沙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至憎妙,卻和暖如春库正,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厘唾。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工褥符, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人抚垃。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓喷楣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鹤树。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铣焊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,099評(píng)論 25 707
  • 當(dāng)我小的時(shí)候,我經(jīng)常想的一個(gè)問題是:如果我和某一個(gè)我羨慕的科學(xué)家或者名人互換身體罕伯,我愿意嗎曲伊?(先不管他愿不愿意) ...
    隨性人啊閱讀 208評(píng)論 0 0
  • 寶貝,新的一周開始啦追他。在上周坟募, 生病了岛蚤。媽媽看到你還是堅(jiān)持早讀,讀經(jīng)婿屹,真的很棒灭美。 昨天去馬博士前,把作業(yè)按時(shí)完成昂利。...
    一縷馨香閱讀 338評(píng)論 0 0
  • DISC性格分析中D型人是“領(lǐng)導(dǎo)型”届腐。這類人最突出的特點(diǎn)是思維敏捷,做事效率高蜂奸,不害怕別人的攻擊犁苏,喜歡創(chuàng)新,行動(dòng)力...
    W南茜閱讀 10,815評(píng)論 0 0
  • 在大洞竹海的萬畝竹海周圍扩所,紅艷艷的映山紅漫山遍野围详,形成萬綠林中一片紅的特有效果。
    徽蘿卜閱讀 468評(píng)論 0 0