一个完美的开发过程是这样的:测试先行,开发人员会些设计一些边界场景的测试用例,比如数据的取值范围从极大到极小、循环语句超出限制范围等等许多极端情况。这些测试代码会作为产品代码的一部分,以自检代码或者单元测试代码的形式与功能代码放在一起。这种类型的测试,开发人员是最适合、也是最有资格去做的人。
对于功能代码而言,思维模式是建设,重点在考虑用户、使用场景和数据流程上;对于测试代码而言,思维模式是破坏,借用代码扰乱用户以及数据。在理想的开发过程里,我们可以把开发人员分为功能开发人员与测试开发人员。
我们还需要一个用户开发人员,他们主要关心的问题是面向用户的任务,包括用例、用户故事、用户场景、探索式测试等等。
上面的这种乌托邦式的理想开发过程,三种角色分工合作,真是完美啊 O(∩_∩)O~
可惜,这种公司在现阶段好像还不存在过,Google 也只是接近这种模式。当前的软件业的发布周期需要以年为单位的客户端模式向每周、每天、甚至每小时都会发布的云端模式转变。Google 的客户端也按照 “云端模式” 来发布,他们的客户端都有一个“自动更新”功能。
Google 的软件测试开发工程师(SET)的职责如下:
公开的代码库(搜索非常便利)、和谐的工程工具、公司范围内的资源共享,这些共享服务依赖于 Google 的基础设施产品,它们会加速项目完成,并且减少了项目失败的风险。
开发人员在维护这些代码时,需要遵守这些规则:
最小化对平台的依赖。所有开发人员的操作系统都尽可能地与 Google 生产环境的操作系统保持一致。对 Linux 发行版本也进行了管理。这样如果一个 bug 在测试机器上出现时,那么在开发机器和生产机器上应该也能复现。
所有对平台依赖的代码,都强制要求使用公共的底层库。Google 使用的每种编程语言,都要求使用统一的编译器,这个编译器针对不同的 Linux 发行版本都会进行持续的测试。限制运行环境可以避免许多与环境相关的那些难以调试的问题。保持简单,也就相对安全。
使用统一的运行平台和相同的代码库,进行持续集成测试、打包。
整体构建流程如下:
这里面包含两个目标:
一个 Google 产品由三部分组成:
为了保证单独的服务可以并行地开发,服务之间的接口需要在项目的早期确定下来,这样开发人员就可以依赖于协商好的接口上。为了保证服务级别之间的早期测试,这些接口一般只做了虚假实现。
在构建目标增长到一定规模时,针对功能集成的小型测试会成为回归测试的一部分。
在以上的活动中,SET 始终是核心参与者。SET 还会同时编写许多的 mock 工具。
SET 也是软件工程师,是一个 100% 的编码角色,他会作为测试人员尽可能早地参与到设计和代码开发流程中去。
SET 是和功能开发人员坐在一起的,这样更容易融入进去。
在面试 SET 的时候,在代码要求上与软件开发工程师(SWE)是一样的,同时还要求 SET 明白如何去测试 SWE 编写的代码。也就是 SET 的要求更高,需要同时了解代码以及测试的问题。
许多创新产品(比如 Gmail 和 Chrome OS)都来源于团队 20% 的业余时间。只有在软件产品变得重要的时候,质量才显得重要。
如果一个产品在概念上还没有完全成型就去关心质量,这是优先级混乱的表现。因此在项目早期就强调测试,是一件非常愚蠢的事情。
Chrome OS 刚开始只有几个开发人员做了原型,且多数都是脚本和虚假实现,他们拿着只是原型的浏览器应用模型做演示,并通过了正式的立项批准。一旦得到正式批准立项,项目的开发总监就会找测试团队,寻求测试资源。
SWE 一般仅在自己的模块领域内提供最优的解决方案,但从整个产品的角度来看,视野略窄,而一个 SET 不仅要具有更广的产品视野,而且在产品的整个生命周期中对产品和功能特性都要做充分的理解。
早期的计划做多少和怎样做比较合适,由创建项目的负责人来做最终的决定。
Google 的技术负责人一般由工程师担任,负责设定技术方向、开展合作、充当与其他团队沟通的项目接口人。
在初期,团队成员一起协同完成设计文档的不同部分,这些文档需要技术负责人的审核。SET 在团队中的优势就是他们拥有产品方面最广阔的视野。
为什么要让 SET 参与审核设计文档:
审核设计文档时,需要带着一定的目的性:
Google 采用的是 protocol buffer 语言,它与编程语言和平台无关,对结构化数据具有可扩展性,但相比 XML 更小、更快、也更简单。开发人员使用 protocol buffer 的描述语言定义数据结构,然后自动生成源代码。
SET 要尽早提供一个可供实施的自动化测试计划。计划必须合情合理而且有影响力。因为投入的越多,维护的成本也会越大,所以需要保证计划规模小而且目的性要强。
SET 会先把容易出错的接口进行隔离,并针对它们创建 mock,这样就可以控制它们之间的交互,从而确保良好的测试覆盖率。
SET 会构建一个轻量级的自动化框架,并使用报表和仪表盘来展示收集到的测试结果以及测试进度,整个过程公开透明,这样获得的代码的质量会大大提高。
SET 要保证系统的可测试性。他是一个质量顾问的角色,为开发人员提供程序结构和代码风格方面的建议,这样开发人员才能更好地做单元测试。SET 还提供测试框架方面的建议,使开发人员能够在测试框架的基础上写测试。
开发人员必须有能力进行代码审查,代码审查有来自工具和公司文化方面的支持。只有被证明是值的信赖的开发者,才能往代码库中提交代码。
Google 把代码审查作为开发流程的中心,因此相对于编写代码而言,代码审查更值的炫耀。
代码已一个“变更列表”(change list,下文会简称为 CL)的单元被编写和封装起来。CL 会被提交审查,Google 使用代码审查工具 Mondrian 发送给具有审核资格的 SWE 或 SET进行审查。
如果 CL 很大,那么审查者会要求把数量较大的 CL 分解为数量较小的几个 CL。有经验和值的信赖的开发人员会得到“可读性”的资格,大家同心协力确保整个代码库看起来像是由一个人编写的一样。
小型测试就是单元测试。它一般集中精力在函数级别的独立操作与调用上,这样的限定可以提供更加全面的底层代码的覆盖率:
范围的隔离而且没有外部依赖,所以小型测试可以在很短的时间内运行结束。这样它们就可以执行的比较频繁,也可以很快发现问题。
中型测试的主要目标是验证指定模块之间的交互,也就是集成测试。鼓励使用模拟技术(mock)来解决外部服务的依赖问题。有的情况下 mock 不能用,那就用轻量级的虚假实现(fake),比如使用常驻内存的数据库。
大型测试就是系统测试,或者端到端测试。它会依赖外部资源,比如数据库、文件系统、网络服务等等。
Google 的测试平台的需要满足的功能是:
当每一个测试都被标注为相应的规模后,调度器可以优化任务队列,达到合理利用的目的。
针对不同测试规模的测试执行时间的目标和限制:
要求 | 小型测试 | 中型测试 | 大型测试 | 超大型测试 |
---|---|---|---|---|
时间目标(每个函数) | 10ms 内 | 1s 内 | 尽可能快 | 尽可能快 |
强制时间限制 | 1 分钟后 | 5 分钟后 | 15 分钟后 | 1小时后 |
不同测试规模的资源使用情况:
资源 | 大型测试 | 中型测试 | 小型测试 |
---|---|---|---|
网络服务 | 是 | 仅本地 | 模拟 |
数据库 | 是 | 是 | 模拟 |
访问文件系统 | 是 | 是 | 模拟 |
访问用户界面 | 是 | 不鼓励 | 模拟 |
系统调用 | 是 | 不鼓励 | 否 |
多线程 | 是 | 是 | 不鼓励 |
睡眠状态 | 是 | 是 | 否 |
系统属性 | 是 | 是 | 否 |
Google 的测试系统会监测某个测试任务是否超时,或者消耗的资源超过了这个测试规模所应使用的资源时,会取消它并报告错误。
优点:
缺点:
优点:
缺点:
优点:
缺点:
小型测试带来优秀的代码质量、良好的异常处理以及优雅的错误报告。中大型测试带来整体产品质量和数据验证。
代码覆盖率的结果会存储在云端,任何开发人员都可以通过内网的网络,使用浏览器来查看这些报告。
总体上的经验法则是:70% 是小型测试,20% 是中型测试,10% 是大型测试。如果项目是面向用户的,拥有较高的集成度,或者用户接口比较复杂,就应该使用更多的中大型测试;如果是基础平台或者面向数据的项目,最好有大量的小型测试。
add 小型、中型、大型测试的优缺点 2017/4/6