數(shù)據(jù)庫(kù)測(cè)試的重要性——永遠(yuǎn)不要忘記數(shù)據(jù)庫(kù)測(cè)試

對(duì)數(shù)據(jù)庫(kù)測(cè)試的根本誤解

有許多關(guān)于測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(Test-Driven Development懒震,縮寫為TDD)的書(shū)籍。那些書(shū)通常關(guān)注的是將測(cè)試應(yīng)用于工作單元(units of work)。對(duì)于工作單元的理解有許多種不同的方式,通常它表示一個(gè)類(class)鬼廓。正如那些書(shū)中所言:編寫許多測(cè)試,以使那些測(cè)試都能通過(guò)的方式創(chuàng)建代碼致盟。應(yīng)模擬所有的外部資源碎税,以便你可以只測(cè)試這個(gè)單元。

這很酷馏锡,但不幸的是所有的測(cè)試在此刻停止了雷蹂。因?yàn)橥ǔ?huì)有些沒(méi)被測(cè)到的查詢(手寫的或者是由某些ORM工具生成的)。有些程序員使用集成測(cè)試來(lái)測(cè)試那些查詢——連接到一個(gè)真實(shí)的數(shù)據(jù)庫(kù)并執(zhí)行真實(shí)的查詢來(lái)進(jìn)行測(cè)試眷篇。這種做法通常意味著在測(cè)試快樂(lè)路徑(happy path)——我已經(jīng)有了ORM工具萎河,所以它會(huì)搞定每件事,我無(wú)須費(fèi)心。

數(shù)據(jù)庫(kù)通常是一家公司最有價(jià)值的資產(chǎn)虐杯。應(yīng)用程序可以一遍一遍重寫玛歌。舊的應(yīng)用程序扔出去,新的應(yīng)用程序裝進(jìn)來(lái)擎椰。但是更換應(yīng)用程序時(shí)沒(méi)人會(huì)丟棄滿載數(shù)據(jù)的數(shù)據(jù)庫(kù)支子。而是將數(shù)據(jù)庫(kù)小心翼翼地遷移過(guò)去。位于多個(gè)系統(tǒng)中的許多不同的應(yīng)用程序會(huì)在同一時(shí)刻使用同一數(shù)據(jù)庫(kù)达舒。這就是為什么擁有充滿約束的良好數(shù)據(jù)庫(kù)模型是如此重要值朋、以及為什么應(yīng)謹(jǐn)慎對(duì)待數(shù)據(jù)庫(kù)的原因。你真的不想破壞數(shù)據(jù)一致性(consistency)巩搏,因?yàn)檫@會(huì)使你的公司付出高昂的代價(jià)昨登。

本文是關(guān)于經(jīng)常被遺忘的數(shù)據(jù)庫(kù)測(cè)試的。使用真實(shí)數(shù)據(jù)進(jìn)行集成測(cè)試贯底。實(shí)際上丰辣,它與你所使用的數(shù)據(jù)庫(kù)引擎的類型無(wú)關(guān)緊要。你可以使用PostgreSQL禽捆、MySQL笙什、Oracle,或者甚至使用那些有趣的noSQL數(shù)據(jù)庫(kù)胚想,例如MongoDB琐凭。以下規(guī)則可適用于各種數(shù)據(jù)庫(kù)和各類應(yīng)用程序。也許不是全部浊服,例如noSQL數(shù)據(jù)庫(kù)就無(wú)法強(qiáng)制實(shí)施數(shù)據(jù)完整性(integrity)统屈。

你的應(yīng)用程序通常是由許多不同的部件組成的。其中有一些<將任何你喜歡的語(yǔ)言放在這里>代碼臼闻,一些配置文件鸿吆,一些SQL查詢,一些外部系統(tǒng)述呐。測(cè)試一個(gè)應(yīng)用程序意味著分別測(cè)試每個(gè)部件(因?yàn)橹挥羞@樣才更容易找出bug)惩淳、以及測(cè)試所有部件是如何協(xié)作的。數(shù)據(jù)庫(kù)就是這些部件的其中之一乓搬,而且你應(yīng)該徹底測(cè)試它思犁。

不測(cè)試數(shù)據(jù)庫(kù)

這是首要的、最可怕的錯(cuò)誤进肯。根本不測(cè)試數(shù)據(jù)庫(kù)激蹲。你編寫了一些使用數(shù)據(jù)庫(kù)的代碼。你甚至使用一些模擬數(shù)據(jù)庫(kù)連接為這些類創(chuàng)建了單元測(cè)試江掩。

集成測(cè)試怎么樣学辱?集成測(cè)試應(yīng)在生產(chǎn)環(huán)境下對(duì)應(yīng)用程序進(jìn)行測(cè)試乘瓤。集成測(cè)試背后的唯一想法是,確保應(yīng)用程序部署到生產(chǎn)環(huán)境后可以正常工作策泣。如果你不在生產(chǎn)數(shù)據(jù)庫(kù)上測(cè)試應(yīng)用程序衙傀,那么你實(shí)際上不并不知道應(yīng)用程序能否工作。你的模擬連接讓你可以發(fā)送尚未檢查以及沒(méi)有檢查的任何查詢萨咕。模擬連接只返回你所需的數(shù)據(jù)统抬。

不創(chuàng)建集成測(cè)試意味著你實(shí)際上沒(méi)有測(cè)試你的應(yīng)用程序。

不測(cè)試數(shù)據(jù)庫(kù)Schema(模式/架構(gòu))

我所觀察過(guò)的大多數(shù)團(tuán)隊(duì)擁有某種形式的集成測(cè)試危队。通常進(jìn)行快樂(lè)路徑測(cè)試:有某個(gè)ORM工具聪建,我們持久化對(duì)象,ORM工具會(huì)完成那些工作茫陆,真是太酷了金麸,我無(wú)須費(fèi)心。

我從未見(jiàn)過(guò)一支對(duì)數(shù)據(jù)庫(kù)schema(模式/架構(gòu))進(jìn)行測(cè)試的團(tuán)隊(duì)簿盅。想象一下钱骂,由于某些針對(duì)產(chǎn)品的查詢很慢,因此你必須在該數(shù)據(jù)庫(kù)中創(chuàng)建某個(gè)索引挪鹏。當(dāng)下次在新的客戶環(huán)境中部署此應(yīng)用程序時(shí),你希望擁有該索引并確認(rèn)該索引真的就在那里愉烙。為什么不編寫一個(gè)簡(jiǎn)單的測(cè)試來(lái)檢查該索引的存在呢讨盒?

除了索引,還有許多要測(cè)試的內(nèi)容:

  • 主鍵(primary keys)
  • 外鍵(foreign keys)
  • 一些檢查——以確辈皆穑“price”(價(jià)格)列不會(huì)有負(fù)值
  • 某些列的唯一性(uniqueness)——你實(shí)際上不想擁有兩個(gè)具有相同登錄名的用戶返顺。

不在生產(chǎn)環(huán)境下測(cè)試

當(dāng)你開(kāi)發(fā)某個(gè)應(yīng)用程序時(shí),你可以從種類繁多的數(shù)據(jù)庫(kù)中進(jìn)行選擇蔓肯。通常你會(huì)從中選擇那個(gè)最好的遂鹊、那個(gè)被團(tuán)隊(duì)所熟知的、或者是由管理層所選定的(有時(shí)使用一些奇怪的理由)蔗包。有時(shí)同一應(yīng)用程序的多個(gè)部署會(huì)在同一時(shí)間使用不同的數(shù)據(jù)庫(kù)引擎秉扑。有時(shí)應(yīng)用程序會(huì)為了能使用不同的數(shù)據(jù)庫(kù)引擎進(jìn)行準(zhǔn)備,因此購(gòu)買此應(yīng)用程序的客戶就可以選擇他想要的數(shù)據(jù)庫(kù)调限。

數(shù)據(jù)庫(kù)引擎的選擇真的與進(jìn)行產(chǎn)品測(cè)試無(wú)關(guān)舟陆。

由于程序員的懶惰,因此他們希望他們的測(cè)試可以運(yùn)行得飛快耻矮。他們不想為測(cè)試結(jié)果等太久秦躯。這也就是為什么許多團(tuán)隊(duì)使用某些更快的內(nèi)存數(shù)據(jù)庫(kù)(例如HSQLDB)的原因。由于那些內(nèi)存數(shù)據(jù)庫(kù)僅存儲(chǔ)在RAM(Random Access Memory裆装,隨機(jī)存取存儲(chǔ)器)內(nèi)存中踱承,而且在操作時(shí)不接觸任何硬盤驅(qū)動(dòng)器倡缠,因此它們的運(yùn)行速度要快得多。

還有一條常常被人遺忘的規(guī)則:

測(cè)試應(yīng)該使用與生產(chǎn)環(huán)境相同的數(shù)據(jù)庫(kù)引擎茎活。

許多程序員會(huì)使用某個(gè)其他引擎昙沦。常見(jiàn)的解釋很簡(jiǎn)單:“我們的數(shù)據(jù)庫(kù)太慢了,我們應(yīng)該使用某個(gè)內(nèi)存數(shù)據(jù)庫(kù)引擎妙色∥ψ蹋”。這并不是個(gè)好主意身辨。這樣你測(cè)試的是該其他引擎丐谋,而非你的生產(chǎn)環(huán)境中的那個(gè),所以實(shí)際上你并沒(méi)對(duì)你的應(yīng)用程序進(jìn)行測(cè)試煌珊。

我曾經(jīng)遇到過(guò)這個(gè)問(wèn)題号俐。我們必須在成功連接數(shù)據(jù)庫(kù)后通過(guò)設(shè)置session變量來(lái)優(yōu)化查詢。那個(gè)應(yīng)用程序在生產(chǎn)環(huán)境中只使用Oracle數(shù)據(jù)庫(kù)定庵。當(dāng)設(shè)置此變量以后吏饿,測(cè)試失敗了。而且是所有的測(cè)試都失敗了蔬浙。原來(lái)是我不能在HSQLDB內(nèi)存數(shù)據(jù)庫(kù)中設(shè)置此變量猪落,因?yàn)樗静淮嬖凇R虼顺氩冶仨毦帉懸欢卧愀獾拇a:在連接后笨忌,檢查數(shù)據(jù)庫(kù)引擎,并由此決定是否設(shè)置此變量俱病。

即使你沒(méi)有任何與混合引擎有關(guān)的問(wèn)題官疲,請(qǐng)記住,當(dāng)你測(cè)試其他非生產(chǎn)環(huán)境的數(shù)據(jù)庫(kù)引擎時(shí)亮隙,你恰恰根本沒(méi)對(duì)你的應(yīng)用程序進(jìn)行測(cè)試途凫。

不準(zhǔn)備好數(shù)據(jù)庫(kù)就進(jìn)行測(cè)試

測(cè)試有一個(gè)通用的、明確定義的流程溢吻。 它非常簡(jiǎn)單:

  1. 準(zhǔn)備環(huán)境
  2. 運(yùn)行一個(gè)測(cè)試
  3. 檢查測(cè)試結(jié)果
  4. 返回至第一點(diǎn)

若嘗試背道而馳维费,則你會(huì)被它所傷。

你察覺(jué)在測(cè)試之后是沒(méi)有整理(tidying)的么促王?

這點(diǎn)非常重要:必須在測(cè)試前準(zhǔn)備環(huán)境掩完,而非測(cè)試之后。你無(wú)法確保測(cè)試將能夠清理一切硼砰。應(yīng)用程序可能因?yàn)槟硞€(gè)錯(cuò)誤且蓬、網(wǎng)絡(luò)連接失敗而退出,或者應(yīng)用程序可能崩潰(例如题翰,由于內(nèi)存不足異常)恶阴。該測(cè)試如何終止并不重要诈胜,真正重要的是該測(cè)試運(yùn)行在為每個(gè)測(cè)試所準(zhǔn)備的相同環(huán)境中。

我曾犯過(guò)這個(gè)錯(cuò)誤:有大量的集成測(cè)試冯事,它們會(huì)在每次測(cè)試后清理所有更改焦匈。許多程序員正使用調(diào)試器來(lái)運(yùn)行這些測(cè)試,并且當(dāng)發(fā)現(xiàn)bug后會(huì)在中間停止測(cè)試昵仅。任何在該測(cè)試之后運(yùn)行的測(cè)試會(huì)得到不可預(yù)知的且隨機(jī)的結(jié)果缓熟。因?yàn)樗\(yùn)行在已被前一測(cè)試所改變的環(huán)境中,而且沒(méi)有為其清理整個(gè)環(huán)境摔笤。

準(zhǔn)備了數(shù)據(jù)庫(kù)卻不對(duì)其檢查就進(jìn)行測(cè)試

在前面的部分中我提到許多有關(guān)準(zhǔn)備數(shù)據(jù)庫(kù)的內(nèi)容够滑。我還想補(bǔ)充一點(diǎn)。準(zhǔn)備數(shù)據(jù)庫(kù)是不夠的吕世。當(dāng)你通過(guò)清理某些表彰触、加載配件等等準(zhǔn)備好數(shù)據(jù)庫(kù)時(shí)……還剩下一件事情要做。

在準(zhǔn)備完畢后命辖,要檢查數(shù)據(jù)庫(kù)狀態(tài)况毅。

你真正需要確保的是你已將一切準(zhǔn)備妥當(dāng)。當(dāng)出現(xiàn)由于bug所導(dǎo)致的某些數(shù)據(jù)留下來(lái)且未能清理時(shí)尔艇,這些工作就可以節(jié)省你的時(shí)間尔许。

這應(yīng)該是測(cè)試前數(shù)據(jù)庫(kù)準(zhǔn)備的一部分。

不測(cè)試創(chuàng)建腳本

每個(gè)應(yīng)用程序都需要某種形式的安裝過(guò)程终娃。而對(duì)于你部署數(shù)據(jù)庫(kù)而言母债,永遠(yuǎn)是第一次。

程序員往往會(huì)通過(guò)手工執(zhí)行某些臨時(shí)的數(shù)據(jù)定義語(yǔ)言(DDL尝抖,data definition language)查詢來(lái)改變數(shù)據(jù)庫(kù)。他們稍后并沒(méi)有把那些語(yǔ)句寫下來(lái)迅皇,或是忘記了所做的改動(dòng)昧辽。他們沒(méi)有更新安裝腳本。大多數(shù)團(tuán)隊(duì)不使用有版本控制的腳本(例如登颓,Ruby on Rails中的Migrations搅荞、或者是Java世界中的Liquibase)。

對(duì)測(cè)試而言最好的方式是框咙,在運(yùn)行測(cè)試套件前重新創(chuàng)建數(shù)據(jù)庫(kù)咕痛。你不必在每個(gè)測(cè)試開(kāi)始前都那么做。只在運(yùn)行所有測(cè)試前運(yùn)行一次就行了喇嘱。

是的茉贡,寧可事先謹(jǐn)慎有余,不要事后追悔莫及者铜。

不測(cè)試外鍵

外鍵是提供數(shù)據(jù)庫(kù)一致性的基本途徑之一腔丧。在良好的關(guān)系數(shù)據(jù)庫(kù)schema中放椰,你應(yīng)該擁有各種鍵。如果你沒(méi)有的話愉粤,那么這可能表明你有一個(gè)真正的大問(wèn)題砾医。然而,這取決于數(shù)據(jù)模型衣厘,但是通常缺乏外鍵是種非常糟糕設(shè)計(jì)的味道如蚜。

測(cè)試外鍵很簡(jiǎn)單。只需在事先沒(méi)有在引用表中添加適當(dāng)?shù)男械那闆r下影暴,為某個(gè)表添加一些行错邦。你應(yīng)該得到一個(gè)錯(cuò)誤。然后坤检,你應(yīng)該從引用表中刪除行兴猩,你可能得到錯(cuò)誤,或沒(méi)有錯(cuò)誤(這取決于該鍵的定義)早歇。無(wú)論如何倾芝,你都應(yīng)該檢查一下預(yù)期行為。

不測(cè)試默認(rèn)值

在良好的數(shù)據(jù)庫(kù)設(shè)計(jì)中箭跳,你應(yīng)該定義一些合理的默認(rèn)值晨另。通常這些默認(rèn)值可能是空(null)。即便這些空也應(yīng)該進(jìn)行測(cè)試谱姓。你不能假設(shè)借尿,只有你的應(yīng)用程序?qū)⒏淖兇藬?shù)據(jù)庫(kù)中的數(shù)據(jù)。\ 兩個(gè)問(wèn)題:

  • 如果某人想創(chuàng)建一個(gè)快速修復(fù)并使用臨時(shí)SQL查詢更新某些數(shù)據(jù)屉来,該怎么辦路翻?
  • 如果有一天某人啟動(dòng)另一應(yīng)用程序,它可以改變這些數(shù)據(jù)茄靠,而且新的應(yīng)用程序?qū)⒉皇褂媚愕腛RM映射或你的DAO(數(shù)據(jù)訪問(wèn)對(duì)象)類茂契,又該怎么辦?

如果你擁有愚蠢的默認(rèn)值慨绳、或是錯(cuò)誤的默認(rèn)值掉冶,那么你可能會(huì)破會(huì)數(shù)據(jù),而且那可能比一個(gè)簡(jiǎn)單的應(yīng)用程序bug更糟糕脐雪。

不測(cè)試約束

在數(shù)據(jù)庫(kù)中還有更多約束厌小,不僅只有主鍵和外鍵約束。你可能擁有一些唯一的(unique)或不為空的列战秋。你可能約束某列只有很少的值集璧亚。你可能想確保價(jià)格永遠(yuǎn)不會(huì)低于0。

良好的數(shù)據(jù)庫(kù)schema應(yīng)擁有許多約束脂信。你也應(yīng)該測(cè)試它們涨岁。如果你希望你的價(jià)格列只能擁有正值拐袜,當(dāng)你嘗試向其中插入-1美元時(shí)會(huì)發(fā)生些什么?為什么不測(cè)試一下呢梢薪?

你不能假設(shè)只有你的經(jīng)過(guò)良好測(cè)試的應(yīng)用程序?qū)⑹褂媚切?shù)據(jù)蹬铺,而且這些檢查是為你防御這些bug的最后一道防線。為什么不測(cè)試它是否正常工作秉撇?

多個(gè)測(cè)試可以更改同一數(shù)據(jù)庫(kù)

通常甜攀,數(shù)據(jù)庫(kù)測(cè)試會(huì)更改數(shù)據(jù)庫(kù)。你可能同時(shí)運(yùn)行多個(gè)測(cè)試琐馆,但是你必須確保那些測(cè)試彼此之間沒(méi)有影響规阀。你必須確保,如果某個(gè)測(cè)試將一些內(nèi)容寫入數(shù)據(jù)庫(kù)瘦麸,而另一測(cè)試將不會(huì)讀到谁撼。

通常,很容易搞得一塌糊涂滋饲,因此我小小的忠告是:避免在同一時(shí)間運(yùn)行多個(gè)測(cè)試厉碟。這也意味著,你不應(yīng)該在多臺(tái)機(jī)器運(yùn)行相同的測(cè)試套件屠缭。

當(dāng)你有許多想運(yùn)行測(cè)試的開(kāi)發(fā)者時(shí)箍鼓,他們每個(gè)人應(yīng)該擁有可用于編寫測(cè)試的單獨(dú)的數(shù)據(jù)庫(kù)。如果你擁有某種形式的只讀數(shù)據(jù)庫(kù)呵曹,沒(méi)關(guān)系款咖,多臺(tái)機(jī)器可以在同一時(shí)間使用這個(gè)數(shù)據(jù)庫(kù)。但是如果你允許所有程序員使用同一數(shù)據(jù)庫(kù)進(jìn)行測(cè)試的情形出現(xiàn)奄喂,那么你可能真的會(huì)得到不可預(yù)知的測(cè)試結(jié)果铐殃。

當(dāng)程序員在某個(gè)測(cè)試中發(fā)現(xiàn)一個(gè)錯(cuò)誤時(shí)會(huì)怎么做?那么跨新,優(yōu)秀的程序員會(huì)盡量修正錯(cuò)誤富腊。如果該測(cè)試失敗僅僅是因?yàn)榱硪怀绦騿T在同一個(gè)數(shù)據(jù)庫(kù)上運(yùn)行他的測(cè)試所導(dǎo)致的話,那么修正此類錯(cuò)誤只是在浪費(fèi)程序員的時(shí)間玻蝌。

沒(méi)有大紅按鈕

優(yōu)秀的程序員是懶惰的。如果你命令優(yōu)秀的程序員每次都重復(fù)同樣的任務(wù)词疼,他們會(huì)越來(lái)越沮喪。優(yōu)秀的程序員會(huì)自動(dòng)化可重復(fù)的事情。

在每個(gè)項(xiàng)目中蝌蹂,你必須在測(cè)試環(huán)境中部署某些東西噩凹。做這些會(huì)花去多少時(shí)間?你真的想為了重新部署應(yīng)用程序和加載數(shù)據(jù)庫(kù)一直浪費(fèi)你的程序員時(shí)間么舵盈?

這就是為什么每個(gè)項(xiàng)目都應(yīng)該有個(gè)大紅按鈕的原因陋率。某位程序員可以按下此按鈕球化,然后沖杯咖啡,回去工作瓦糟,并且?guī)追昼姾蟮弥拇蠹t色按鈕完成的工作筒愚,一切準(zhǔn)備就緒。

大紅按鈕真的會(huì)為你節(jié)省很多時(shí)間菩浙。你會(huì)說(shuō)自動(dòng)化所有工作實(shí)在太緩慢巢掺。然而,事實(shí)并非如此劲蜻。恰恰相反陆淀,就像說(shuō)測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(TDD,Test-Driven Development)很慢一樣先嬉。在最初的時(shí)候比較慢轧苫,但隨著項(xiàng)目變得更加復(fù)雜,由于存在測(cè)試或按鈕疫蔓,會(huì)為你節(jié)省更多的時(shí)間含懊。各種各樣的大紅按鈕——你可以用它們部署應(yīng)用程序、運(yùn)行測(cè)試鳄袍,以及類似的后方支援绢要。

有時(shí)會(huì)使用Jenkins(又名Hudson)來(lái)做這些。是的拗小,對(duì)于此類大紅按鈕而言這是一款偉大的軟件重罪。唯一的事情是,每位程序員應(yīng)該有其自己的一組工作以便在其自己的環(huán)境中部署所有的內(nèi)容哀九,在其自己的環(huán)境中他(或她剿配,當(dāng)然)可以自由發(fā)揮,而不會(huì)影響他人阅束,同樣也不會(huì)受到他人的影響呼胚。

工具

有許多數(shù)據(jù)庫(kù)測(cè)試工具。為了測(cè)試整個(gè)schema息裸,你可以編寫簡(jiǎn)單的集成測(cè)試蝇更。對(duì)于PostgreSQL有pgTAP,使用TAP插件它可以與Jenkins集成到一起呼盆,因此Jenkins可以擁有一項(xiàng)用于測(cè)試數(shù)據(jù)庫(kù)(包括生產(chǎn)數(shù)據(jù)庫(kù))是否正常的工作年扩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市访圃,隨后出現(xiàn)的幾起案子厨幻,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件况脆,死亡現(xiàn)場(chǎng)離奇詭異饭宾,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)格了,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門看铆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人笆搓,你說(shuō)我怎么就攤上這事性湿。” “怎么了满败?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵肤频,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我算墨,道長(zhǎng)宵荒,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任净嘀,我火速辦了婚禮报咳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挖藏。我一直安慰自己暑刃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布膜眠。 她就那樣靜靜地躺著岩臣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宵膨。 梳的紋絲不亂的頭發(fā)上架谎,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音辟躏,去河邊找鬼谷扣。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捎琐,可吹牛的內(nèi)容都是我干的会涎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瑞凑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼末秃!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起拨黔,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蛔溃,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后篱蝇,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體贺待,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年零截,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了麸塞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涧衙,死狀恐怖哪工,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弧哎,我是刑警寧澤雁比,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站撤嫩,受9級(jí)特大地震影響偎捎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜序攘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一茴她、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧程奠,春花似錦丈牢、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至帕识,卻和暖如春泛粹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肮疗。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工晶姊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伪货。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓们衙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親碱呼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蒙挑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348