《Google软件测试之道》读书笔记

作者按:学习软件测试。与其说是读书笔记就是我个人的记录。

第一章 Google软件测试介绍

“Google是如何测试的?”
在Google,软件测试团队归属于一各被称为“Engineering Productivity”的中心组织部门,这个部门的职责横跨开发测试人员使用的工具研发、产品发布和各种级别的测试,从单元级别的测试到探索性级别的测试。Google拥有大量针对互联网产品的共享工具和测试基础框架,服务于包括搜素、广告、Apps、YouTube视频和其他Google在Web上提供的产品。

其实可以看出Google在发展的过程中,逐步把测试提到与开发同等重要的位置。

有时,测试和开发相互交织在一起,达到了无法区分彼此的程度,而在另外一些时候,测试和开发有时完全分离的,甚至开发人员都不知道测试在做些什么。

测试和开发的关系一直也是一个值得思考的问题。

以开发为中心的文化中Google是如何做测试的。

1.1 质量不等于测试

为了解决这个问题,开发和测试应该并肩齐驱。测试不是独立隔离的活动,它本身就是开发过程中的一部分。质量不等于测试,当你把开发过程和测试放到一起,就像搅拌机例混合搅拌那样,直到不能区分彼此的时候,你就得到了质量。
单元测试由开发人员完成。这意味着质量更像是一种预防行为,而不是检测。

1.2角色

我们明确地 提出了有一种工程师角色必须存在,他可以让开发人员更有效且高效地做测试。这些角色常把自己看做是测试者,但实际上他们的使命是提高生产率。

1.2.1软件开发工程师(SWE)

几乎把所有的时间都花费在代码编写上。

1.2.2软件测试开发工程师(SET)

这也是一个开发角色,只不过工作重心在可测试性和通用测试基础框架上。他们参与设计评审,非常近距离地观察代码质量和风险。为了增加可测试性,他们甚至会对代码进行重构,并编写单元测试框架和自动化测试框架。SET是SWE的合作伙伴,相比较SWE是在增加功能性的代码或是提高性能的代码上,他们这样做的目的是为质量服务,而SWE则更关注用户使用功能的开发实现上。

1.2.3测试工程师(TE)

这是一个与SET关系密切的角色,有自己不同的关注点——把用户放在第一位来思考,代表用户的利益。一些Google的TE会花费大量的时间在模拟用户的使用场景和自动化测试脚本或代码的编写上。同时,他们会把开发工程师和SET编写的测试分门别类地组织起来,分析、解释、测试运行结果,驱动测试执行,构建端到端的自动化测试。特别是在项目的最后阶段,推动产品发布。TE是真正的产品专家、质量顾问和风险分析师。某些TE需要编写大量的代码,而另外一些TE只需要编写少量的代码。
从质量的角度来看,SWE负责功能实现和这些独立功能的质量。他们对容错设计、故障恢复、测试驱动设计、单元测试负责,冰河SET一起编写测试代码。
SET也是开发人员,负责提供测试支持。有这样一个测试框架,它可以把新开发的代码隔离,通过模拟一个真实的工作运行环境和代码提交队列来管理代码的提交。换句话说,SET编写代码,通过这些代码提供的功能让SWE能后自己测试他们的功能。多数测试代码是由SWE完成,SET存在的目的就是保证这些功能模块具有可测试性,并且相应的SWE还可以积极地参与到测试代码的编写中去。
很明显,SET的主要关注对象是开发人员。SET的主要职责是让开发者可以很容易的编写测试代码。专注于用户角度的测试则是TE的职责。考虑到SWE和SET已经做了足够多的模块级别与功能级别的测试,下一步要考虑的就是要验证这些可执行的代码与数据集成在一起之后,是否可以满足用户的需求。TE扮演两种角色:

  • 确认开发人员在测试方面的工作是否到位;
  • 站在用户的使用家督,是否满足性能期望,在安全性、国际化、访问权限等方面是否满足用户的需求。

1.3组织结构

理论上讲,测试人员和开发人员属于同一个工程产品团队。在组织结构上,开发人员和测试人员汇报同一个产品团队的管理者。但实际上都不是这样。
测试是一个单独的部门,哪一个产品 有需求,就从测试团队调人过去做一些质量方面的工作。这种测试人员在不同的项目之间的借调模式,可以让SET和TE时刻保持新鲜感并且总是很忙碌,另外还可以保证一个好的测试想法可以快速在公司内部蔓延。对于公司来说,就不用需要太多的测试人员了。从整个公司的角度看,需要保持对各个产品和技术都了解的测试人员的存在。

我觉得这个想法很棒!

1.4爬、走、跳

在拥有如此少量测试人员的情况下,Google还可以取得不错的成果,核心原因在于Google从来不会在一次产品发布中包含大量的功能。在一个产品的基本核心功能实现之后,就立刻对外发布使用,然后从用户那里得到真实反馈,再进行迭代开发。
一个产品走向成熟的多个版本。

1.5测试类型

Google着重强调的是测试的范畴规模而非形式。分为:

  • 小型测试(单元测试):一般来说都是自动化实现的,用于验证一个单独的函数或独立功能模块的代码是否按照预期工作,着重于典型功能性问题、数据损坏、错误条件和off-by-one(大小差一错误是一类常见的程序设计错误)等方面的验证。小型测试由SWE实现,也会有少量的SET参与,TE几乎不参与小型测试。小型测试主要尝试解决的问题是“这些代码是否按照预期的方式运行”。(虚拟fake场景)
  • 中型测试(集成测试):通常也是自动化实现的。一般会涉及两个或两个以上的功能模块之间的交互。重点在于验证这些“功能近邻区”之间的交互,以及彼此调用时的功能是否正确。在产品早期开发过程中,在独立模块功能被开发完毕后,SET会驱动这些测试的实现与运行,SWE会深度参与,一起编码、调试和维护这些测试。后期,TE加入。中型测试要解决的问题是:一系列临近的模块相互交互的时候,是否如我们预期的那样工作。(fake或真实场景)
  • 大型测试(系统测试):涵盖更多的功能模块,使用真实用户使用场景和实际用户数据。关注点在于所有模块的集成,验证软件是否满足用户的需求。SWE、SET和TE都参与。大型测试尝试解决的问题是:这个产品操作运行方式是否和用户的期望相同,并产生预期的结果。这种端到端的使用场景以及整体产品或服务之上的操作行为,即大型测试关注的重点。(真实场景和真实数据)

第二章 软件测试开发工程师

在过去几年中,工业界使用了各种特定术语来描述这些辅助设施,包括测试框架、测试通用设施、模拟设施(moke)、虚拟设施(fake)。在假想的完美开发过程中,在你做功能测试时,如果需要,这些工具都应该及时出现在你眼前,任你使用。但是实际情况却不是这样的。
对于feature code,思维模式是创建,重点在考虑用户、使用场景和数据流程上;对于test code,主要思路是破坏,怎么写测试代码用以扰乱分离用户及其数据。

2.1 SET的工作

随着Google的不断壮大,出现了第一个融合开发角色和质量意识于一身的角色——SET。

2.1.1开发和测试流程

公开的代码库,和谐的工程工具、公司范围内的资源共享,成就了丰富的Google内部共享代码库和公共服务。
现在,你完成了一个Google产品,它由三部分组成:一个经过良好测试的独立库、一个在可读性和可复用性方面都不错的公共服务库(这个服务库中还包含另外一套支持库,可以用来创建其他的服务)、一套覆盖所有重要构建目标的单元测试套件。
在所有的这些活动中,SET始终是核心参与者。他们在开发人员不知道哪些地方需要单元测试的时候明确指出。他们同事编写许多moke和fake工具。他们甚至编写中大型集成测试。

2.1.2 SET究竟是谁

SET首先是工程师角色。SET是软件工程师,是一个100%的编码角色。这种测试方法可以使测试人员通过设计和代码开发的方式尽早介入到开发流程中去。
在面试SET时,在代码要求标准上与SWE的招聘要求是一样的,而且增加了一个额外的考核——SET需要了解如何去测试他们的代码。换句话说,SWE和SET都需要回答代码问题,而且SET还要求去解答测试问题。

2.1.3 项目的早期阶段

一个产品如果在概念还没有完全确定成型时就去关心质量,这就是优先级混乱的表现。当然,物极必反,风险总是相对的。如果一个产品太长时间没有测试的介入,早期在可测试性上的糟糕设计在后期很难去做改进,这样会导致自动化难以实施且测试工具极不稳定。在这种情况下,不得不以质量的名义来做重构。这样的质量“债”会拖慢产品的发布,甚至长达数年之久。
没有项目会认为如果得不到测试资源,他们的产品就将不会存在,开发团队在寻求测试帮助的时候,有义务让测试人员相信他们的产品是令人兴奋且充满希望的。

2.1.4 团队结构

SWE一般仅在自己的模块领域里提供最优方案,但如果从整个产品的角度来看,事业会显得略微狭窄。一个好的SET正好可以弥补这一点,不仅要具有更宽广的整体产品视野,而且在产品的整个生命周期里对产品及功能特性做充分理解,许多SWE来往穿梭于不同产品,但产品的生命周期比SWE待在产品里的时间要长久的多。
产品:良好的文档,不错的可测试性、运行着稳定的自动化测试、清晰的代码提交流程。
项目的技术负责人和发起人要做的第一件事就是设计文档。随着文档的不断完善,就需要不同专业类型的工程师角色投入到项目中去。许多技术负责人期望SET在早期就能参与项目,即便那时SET资源还相对稀缺。

2.1.5设计文档

动态,随项目的进展更新。
实际上,作为工程师,SET在团队中有一个巨大的优势,就是拥有产品方面最广阔的事业。一个好的SET会把非常专业的广阔事业转化为影响力,在开发人员所编写的代码上产生深远的影响力。通常来说,代码复用和模块交互方面的设计会由SET来做,而不是SWE。
在设计阶段,SET在推进项目的同时也可以简化相关项目成员的工作。
SET审阅设计文档。审阅设计文档的时候应该有一定的目的性。强烈的目的性要点:

  • 完整性:找到文档中残缺不全或一些需要特殊背景知识的地方。通常情况下团队里没人会了解这些知识,特别是对新人而言。鼓励文档作者在这方面添加更多细节,或添加一些外部文档链接,用以补充这一部分背景知识。
  • 正确性:开一下是否有语法、拼写、标点符号等方面的低级错误。
  • 一致性:确保配图和文字描述一致。确保文档中没有出现与其他文档中截然相反的观点和主张。即使有,也要写明原因。
  • 设计:文档中的一些设计要经过深思熟虑。考虑到可用的资源,目标是否可顺利达成?要使用何种基础的技术框架(读一读框架文档并了解他们的不足)?期望的设计在框架方面使用用方法上是否正确?设计是否过于复杂?有可能简化吗?还是太简单了?这个设计还需要添加什么内容?
  • 接口与协议:文档中是否对所使用的协议有清晰的定义?是否完整地描述了产品对外的接口协议与协议?这些接口协议的实现是否UI他们期望的一致?是否鼓励开发人员自定义Protocol buffer数据格式?
  • 测试:系统或文档中描述的整套系统的可测试性怎样?是否需要新增测试钩子(testing hook,这里是指为了测试而增加一些接口,用以显示系统内部状态信息)?如果需要,确保他们也被添加到文档之中。系统的设计是否考虑到易测试性,而为之也做了一些调整?是否可以使用已有的测试框架?预估一下在测试方面需要做那些工作,并把这部分内容增加到设计文档中去。

2.1.6接口与协议

开发人员使用Protocol buffer的描述语言来定义数据结构,然后使用自动生成的源代码,可使用任何一种编程语言从各种数据流中来读或写这些结构化的数据。

2.1.7自动化计划

试图在一个测试套件中自动化所有端到端的测试用例,是一个常见的错误。
规模更小且目的性更强的自动化计划,并存在可以提供帮助的测试框架。
在端到端的自动化测试上过度投入,常常会把你与产品的特定功能设计绑定在一起,这部分测试在整个产品稳定之前都不会特别有用。
在Google,SET遵循下面的方法:
1)首先把容易出错的接口做个李,并针对它们创建mock和fake。
2)其次,构建一个轻量级自动化测试框架,控制mock系统的创建和执行。

2.1.8 可测试性

Google的代码流程:
作为开发人员,一个基本的要求就是有能力做代码审查。为了使SET也称为源码的拥有者之一,Google把代码审查作为开发流程的中心。
“可读性”用以区分有资格提交代码的人和新开发人员。
代码在Change LIst(CL)编写和封装,CL在编码结束之后会提交审查,Mondrian(Google App Engine上运行着一个开源版本的Mondrian)会把需要审查的代码发送给具有审阅资格的SWE或SET。
CL里面可以封装一段新代码或者对已有代码的修改、缺陷修复等。
大家同心协力确保整个代码库看起来像是一个人编写的一样。

2.1.10测试执行

测试自动化不仅仅是自动化测试程序的编写,还需要考虑如何编译测试程序、执行、分析、存储和保高速由测试运行结果。
除了要关注如何正确编写自动化程序之外,还要把工程师的注意力转移到在实际项目中如何更大发挥自动化测试的价值上。只有能加速开发过程的自动化过程才有意义,测试不应拖慢开发过程。
因此,一个可以做代码编译、测试执行、结果分析、数据存储、报表展示的通用的测试框架逐渐形成了。
在SET新增一个测试程序之后,同时会针对这个测试创建一个构建说明文件。这个测试程序的构建文件包括测试名称、源码文件、依赖库及数据、还要指明测试规模大小。每一个测试程序必须标明它的规模是小型、中型、大型还是超大型。在编写完测试程序和构建文件之后,后面就交给Google构建工具和测试执行框架了。
为了契合测试执行框架,就对编写测试程序有一定的要求限制。

2.1.11测试大小的定义

测试类型方面的专业术语:单元测试、代码级别测试、白盒测试、集成测试、系统测试、端到端测试等、从不同的粒度级别来描述测试的类型。下面对测试规模的描述和定义都是Google内部对测试规模的定义。
1、小型测试:
小型测试是为了验证一个代码单元的功能,一般与运行环境隔离,例如针对一个独立的类或一组相关的函数的测试。小型测试的运行不需要外部依赖。在Google之外,小型测试通常就是单元测试。
小型测试的精力一般集中在函数级别的独立操作与调用上。提供更加全面的底层代码覆盖率。
测试时间:开发人员修改了他们的功能代码之后就会立刻执行这些测试。
2、中型测试:
中型测试是验证两个或多个模块应用之间的交互。主要目标是验证指定模块之间的交互。在Google之外,中型测试经常被称为集成测试。
由SET组织运行测试执行工具执行中型测试。
3、大型测试:
在Google之外,被称为系统测试或端到端测试。验证系统作为一个整体是如何工作的。这涉及应用系统的一个或所有子系统,从前端界面到后台数据存储。

2.1.12测试规模在共享测试平台中的使用

为每个测试划定规模大小,就可以优化任务队列,达到合理利用的目的。

2.1.13测试规模的益处

每种规模的测试的优缺点。
检验一个项目里的小型测试、中型测试和大型测试之间的比率是否健康,一个好办法时使用代码覆盖率。测试代码覆盖率可以针对小型测试、中大型测试分别单独产生报告。
这个比例并不是固定的,总体上有一个经验法则,即大型:中型:小型=10:20:70。如果一个项目是面向用户的,拥有较高的集成度,或者用户接口比较复杂,他们就应该有更多的中型和大型测试;如果是基础平台或者面向数据的项目,例如索引或网络爬虫,则最好有大量的小型测试,中型测试和大型测试的数量要求会少很多。

2.1.14测试运行的要求

测试本身要满足下面几个条件:

  • 测试与测试之间是相互独立的,完全可以以任意顺序来执行。
  • 测试不做任何数据持久化的工作。测试环境的状态不发生改变。
    传统的持续集成存在的问题:对出错的代码难以精确定位。
    Google提供的持续集成系统使用构建系统中的构建依赖原则。在这个规则中描述了代码是如何编译的,数据文件是怎样集成在一起成为应用程序的,以及测试如何运行等信息。
    依赖图。当某一个模块的代码修改之后,可以在依赖图中找到与这个模块相关的测试。这就是构建依赖原则。

Google的软件测试方法虽然具有明显的优点和优越性,但是执行起来没有那么容易。

2.2 测试认证

这部分讲的是Google公司内部对于开发人员测试的培训,使功能开发人员建立对代码进行小型测试的观念。

2.3SET的招聘

Google认为一个优秀的SET各方面应该都很出色:是一个编码能力很强的程序员,可以写功能代码;也是一个能力很强的测试者,可以测试任何产品,有能力管理他们自己的工作和工具。Google对属于算法还是有要求的。作者在这里举了一个例子:
作为一个SET,假如你第一天上班,被要求去实现一个函数account(void* s),返回一个字符串中大写字母A出现的次数。
SWE的做法是上来就写代码,但SET不应该这样。SET需要先搞清楚这个函数是用来做什么的?我们为什么要构建它?这个函数的原型看起来正确吗?SET应该关注函数的正确性以及如何验证代码是否达到期望的行为。相反,SWE就要关注如何写最少的代码,最快的效率,最优的求解方式。
另外如果面试的时候公司提出一个问题是给一个模块增加测试场景,其实公司不希望SET上来就罗列所有的可能的测试用例,而是希望SET先执行最佳(所谓最佳,就是针对待测模块最核心的问题开始测试)的测试用例。因为SET的时间是有限的。SET应该能够回过头来虚招最有效的解决问题的方法,为先前的函数定义可以做一些改进。
普通的候选人会花几分钟通过提问和陈述的方式来理解需求文档。例如:

  • 输入输出参数
  • 函数名字比较糟糕,是否有命名规范?
  • void* 是危险的,我们应该考虑char*
    更好的候选人则会考虑:
  • 扩展性、复用性、安全性等
    最佳候选人:
    比较多,详见书第64页。

我觉得书中的提到的最佳候选人的思考方式是一个有经验的SET才能想到的。一般初出茅庐的大学生对项目的认识不是很广泛,所以一般看不到这么广,想不到这么深。

在面试者中需要另外考虑的是文化上是否匹配。SET候选人在面试过程中是否在技术上有好奇心?当面对一些新想法的时候,候选人是否能够把它融入到解决方案例?优势如何处理有歧义的地方的?是否熟悉质量方面的理论学术方法?是否理解质量度量或其他领域的自动化?当SET发现在实现中存在缺陷时,是否心存戒备,思路是否足够开阔?这些与TE的要求又有所不同。

首先,中国市场已经不需要测试工程师(TE)了,互联网公司需要他们的测试文能写测试,武能写代码。虽然对SET的代码能力的要求不如对SWE的要求高,但是需要SET具有强大的代码走读能力和理解能力。

2.4 与工具开发工程师Ted Mao的访谈

这些访谈虽然可能有用,但与Google产品紧密相关,作为局外人(读者)很难体会到当中的经验和当事人的感想。

第三章 测试工程师

软件测试开发工程师(SET)负责可测试性和测试自动化体系的长期有效性。测试工程师的职责与之有所不同,TE的重点在于评估对用户的影响以及软件产品整体目标上的风险。对于TE的编码能力就没有那么高的要求了。

3.1 一种面向用户的测试角色

大多数的TE都会从事一些基础技术层的、需要另外一种视角和较强的专业技术能力的工作。这一切都与风险有关:TE以对某种(某类)特定的产品最合适的方式发现软件中风险最大的地方并尝试减少或消除它。
SET和TE的重点不同,早期的工作涉及更多的面向SET的任务,而项目后期才是面向TE的任务。

3.2 测试工程师的工作

早期的测试计划需要较少的TE,而在产品接近尾声、寻找Bug变得更加紧急的时候,需要较多的资源投入到测试上进行探索式测试。因为在某种产品研发的早期阶段,功能还在不断变化,最终功能列表和范畴还没有确定,TE通常没有太多的工作可做。
当TE进入产品的时候,并不需要从0开始。SWE和SET已经在测试技术和质量方面做了大量的工作,可以作为TE的起点。TE在进入产品时,需要考虑以下问题:

  • …… (详见书77)
    TE的根本使命是保护用户和业务的利益,使之不受到糟糕的设计、令人困惑的用户体验、功能bug、安全和隐私等问题的困扰。
    TE有时候需要与个性很强的开发和产品人员打交道。TE的沟通能力要强。
    这个角色需要敏锐的洞察力和领导力。

文中也提到很多Google的高级测试经理们都来自于TE。其实测试工程师需要有技术能力、领导力、深刻理解产品的能力等等,这些能力也是一个产品经理需要具备的。

关于TE职责的一般性描述

  • 测试计划和风险分析
  • 评审需求、设计、代码和测试
  • 探索式测试
  • 用户场景
  • 编写测试用例
  • 执行测试用例
  • 众包(外包)
  • 使用统计
  • 用户反馈

3.2.1测试计划

实际上,一般情况下,我们都认为SWE的工作更有交织,他们编写代码,构建用户期望的、能为公司赚钱的应用。很明显,代码是项目过程中产生的最重要的文档。
但是,测试人员要处理的是真正的文档和其他临时性的事物。在项目的早期阶段,测试人员编写测试计划;然后,他们创建和执行测试用例,编写bug报告;接下来是准备覆盖季度报告,收集用户满意度和软件质量数据。在软件成功发布(或失败)之后,很少有人会问及测试产物是什么。如果软件深受用户喜爱,大家就会认为测试所做所为是正当的;如果软件很糟糕,人们就会质疑测试的工作。其实也没人真正想去理解测试到底做了什么。

Google是真的将他们的工程师一视同仁,并且对于每一个工作角色的任务分工都很明确。

作为测试文档,测试计划是必须的。但是测试计划是最早出现、最先被遗忘的测试产物。
在项目早期,测试计划代表了对软件功能的预期。但是除非得到持续关注,他会很快锁着新代码的完成、功能特性的改变以及设计的调整而国企。伴随着计划内或计划外的变更,维护一份测试计划是要花费大量的精力的。除非大多数项目的成员会定期查看,否则测试计划并没什么价值。
理想情况下,测试计划应当在项目执行中发挥核心作用,应当在软件的整个生命周期中持续有效:随着代码库的更新而更新,时刻代表最新的产品功能,而不是停留在项目开始阶段时的样子。她应该可以帮助一个新加入的工程师迅速更上项目进展。
Google希望测试计划具有的特性如下:

  • 需要及时地更新
  • 描述了软件的目标和卖点。
  • 描述了软件的结构、各种组件和功能特性的名称。
  • 描述软件的功能和操作简介
    对于如何制定测试计划,本书在此处给出了ACC测试建模方法。以下所述ACC相关内容参考测试建模:Google ACC.
    ACC(Attributes Compontents Compatibilities)是Google测试团队使用的一种建模方法,用来快速地建立产品的模型,以指导下一步的测试计划和设计。
    运用ACC建模的第一步是确定产品的Attributes(属性)。按照Google的定义,Attributes是形容产品的词语,是与竞争对手区别的关键特征。按照敏捷开发的观点,Attributes是产品所具有的核心价值。以Google+为例,Google+的Attributes如:Social(社交)、Expressive(表现力)、Easy(便捷)、Relevant(只显示用户感兴趣的内容)、Extensible(能够与Google的已有功能、第三方网站和应用集成)、Private(用户数据不会泄露)等等。
    ACC以Attributes
    开始,是产品竞争的自然选择,也符合Google的开发实践。一般情况下,一个互联网公司中,SWE+STE的人数要远远多于TE的人数。前两种角色会编写大量的自动化测试用例,对产品实施周密的测试,所以TE主要面向用户,主要关注用户价值和系统级测试。但是TE没有足够的资源测试用户的行为。所以,TE需要通过确定Attributes来明确产品的核心价值,从而区分测试对象
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容