阿里云「飞天发布时刻」2024来啦!新产品、新特性、新能力、新方案,等你来探~ 了解详情
写点什么

一种有效的测试策略

  • 2014-05-27
  • 本文字数:3257 字

    阅读完需:约 11 分钟

在最近的一个大型项目中,我们在早期就定下了一个目标:不会在软件中使用大量 QA 人员专注于手工测试。通过手工测试发现 bug 极其耗时且成本高昂,这促使团队尝试尽可能的将质量内嵌到产品内部。但这并不意味着手工测试毫无价值,因为人们总能在怎样使用软件上给你一些特别的惊喜。

这是一个为期 18 个月左右,周期很长的项目,并且后续也会持续更新。 在项目初期,团队就意识到项目成功的重中之重在于一个优秀的测试策略,尤其是让我们的团队能够做到:1) 随着项目时间的推移能够持续的提高团队的工作效率。2) 不管面对的变更是大是小都能够具有足够的信心。

我们花费了很长时间才确定了一种有效的策略。这在很大程度上是因为我们不得不学习怎样让我们的程序在所有层上都具有可测性。虽然所有的项目团队成员都具有 TDD(测试驱动开发)的经验,但仅仅这样并不足以建立有效的测试策略。

测试分层

给不同的测试分类是一件令人烦恼的事。有功能测试,集成测试,单元测试,验收测试,slow tests,fast tests,UI 测试…等等等等。然后我们发现属于我们的测试主要有三种类型:

  • 系统测试
  • 皮下测试
  • 单元测试

它们之间的区别主要在于被测试内容的范围。系统测试指的是通过应用的外部接口进行运作,无论对象是一个浏览器,文件下拉菜单,队列,window 窗体应用或者其他的什么东西。

皮下测试运行在外部用户接口之下。如果测试的是 Web 应用,皮下测试在我们理解就是指在真实的类
以及环境部署到位的情况下,通过命令处理器进行发送的表单对象。绕过 UI 层逻辑,直接到达 domain 层。发送表单对象,抛出”成功 / 失败”的执行结果。

对于最底层而言,我们有单元测试。单元测试用于测试一个类,并且可以是 fast test 或者 slow test 中的一种。Fast Test 即是常规的 TDD 测试,用于增量的类设计。Test doubles 曾被认为是必要的,但是除非系统交互非常值得关注,否则严格的 基于交互的测试 并不是那么有价值。我们同样也有 slow 单元测试,其同样可被分类为 交互测试。当然它们同样可归类为 repository tests, persistence tests 等。

单元:皮下:系统 测试在我们的测试工作中各自占的比重差不多是 10:2:1。 为了完成项目我们做了大约 5000 个单元测试,1000 个皮下测试,500 个使用 WaitN 以及 Gallio 驱动浏览器的系统测试。6000 个单元 / 皮下测试的执行时间大概是 10 分钟,而剩下的 500 个 UI 测试大概需要 50 分钟完成。

单元测试策略

单元测试是在严密的 TDD 模式下开发的。我们在功能实现之前编写单元测试,并用这些测试驱动代码设计。这些测试可以帮助发现设计问题、封装问题、代码异味等。

我们努力避免编写纯粹用于提供测试的代码。它们常常意味着我们有设计问题、责任错位或封装已被破坏。

随着我们越来越深入项目管道,我们对交互测试的重视越来越少。 如果你真的对交互感兴趣,那么通过 mock 进行的交互测试也仅仅是有趣而已。但更多的时候,我们更感兴趣的是附加作用,而交互只是一个实现细节。反之,我们经常做的是模拟(mock)出过慢或不可测的代码,比如存储库、基于外部服务的外观、配置类等等。否则,我们有限的模拟只是模拟了我们感兴趣的那些观察点。

在大型项目中的某些时间点,为了提取出能加快功能交付的理念,设计往往需要做大型的重构。在我们上一个项目中,我们发掘出了如下理念:

  • AutoMapper
  • 将表单作为单独的命令消息处理
  • Input builders

有了以上这些,单元测试是重构时的保障。但只有我们依赖这些测试来捕获应用程序中所有有趣的行为时,才能有保障的作用。为了允许有效的大中型重构,我们需要增加额外的测试层级。

皮下测试策略

皮下测试,顾名思义,所有的测试都是在用户界面之下进行的。在 MVC 应用程序中,皮下测试是测试控制器下面的所有内容。对于 Web service,一切测试都在终端下进行。皮下测试的思想是,应用程序的最上层不执行任何实际的业务逻辑,而只是外部接口与底层服务之间的连接。

皮下测试的重要性体现在我们希望在抛开如用户接口和外部服务这类外部连接点的情况下,能够在整个系统运行的同时测试业务逻辑。相对于单元测试关注小模块的设计,皮下测试关注的不涉及设计,而是测试整个系统的基本输入和输出。

要建立有效的皮下测试,我们可以尝试通过常见的逻辑流程建立 uniform pinch points。例如,我们可以建立一个命令消息处理系统,或一个普通的查询界面。在最近的一个处理批处理文件项目上,批处理文件中的每一行都被转换为一条消息。然后,我们创造一条消息,发送给这个系统,然后验证处理该消息的所有异常情况。

由于皮下测试不是基于设计而是基于高级(业务)行为,它们是理想的基于场景的测试策略,如 BDD 或 Testcase Class per Fixture 模式。如果我们要进行大的重构,我们需要这些高层次的测试,为商业行为建立全面的安全保障。由于皮下测试更关注于端对端的逻辑,所以它也是标志功能点完成的一个重要的目标点。

虽然皮下测试使我们能够安全地执行较大的重构,但它仍无法保证我们可以放心地将系统升级到生产环境。

全系统测试策略

起初,我们把全系统测试称为“UI 测试”,直到我们的项目越来越多地牵涉到集成策略。这时输入到我们系统中的不再是浏览器,取而代之的是消息,来自 REST 端点、FTP 或批处理文件。UI 测试只是全系统测试的一个子集。全系统测试背后的思想是,我们想按照软件在生产环境中的使用方式来测试它们。对于一个 MVC 应用程序来说,就是基于浏览器的测试。对于批处理文件来说,我们会使用实际的文件。对于 REST 使用实际的 HTTP 请求。对于消息则使用实际的队列和消息。

如果我们想知道,应用程序在部署到生产环境之前是否能按照预期工作,一个有效而且高效的方法是,创建一个自动化测试来测试整个系统。如果我可以让 UI 测试登录到应用程序中、创建一个订单,然后我可以验证是否产生了一个订单请求,那么我会感觉很良好。

关于全系统测试的一个常见误区是认为它就是黑盒测试。然而,全系统测试的特点在于,你必须对系统内部发生的事情了如指掌。实际上,全系统测试甚至还可以利用域模型来生成数据,而不是一个纯粹为测试目的而构建的系统后门。很多团队容易掉进去的一个大坑是,不按照与生产环境一样的代码路径来测试,这将导致系统处于古怪的、无效的、很难处理的状态。

在我们的项目中,全系统测试代码是我们在声称一个功能 / 故事做完之前的所写的最后代码。对于描述一个功能的“已完成”特性来说,手工测试的成本太高、而且不可靠。但是,如果我能像在生产环境一样去测试,通过完全一样的外部界面来完成,那这样的手工测试也算是成功的。

全盘考虑

在一个未经测试过的应用程序中,作为提高覆盖率的手段,我们发现实际上最有价值的测试策略是从全系统测试开始,然后往下移,直至单元测试。我们先做最宽松、最简单的断言,然后慢慢往下移,直至单元级别的逻辑。在全新开发的应用程序中,我们倾向于不只是特别关注某一个区域,因为对于一个需要长期维护的系统来说,所有的测试都很重要。

这种测试策略确实需要一定的投资。我们发现,当我们知道这个应用程序对客户的业务有决定性作用的时候,这样的全盘考虑在特别有效。如果一个应用程序对业务有决定性作用,那它将不得不面临变更。当变更来临的时候,我们最好能安全地实施变更而不影响客户的业务。

1. 作者简介

Jimmy Bogard 是德克萨斯州 Headspring 公司的技术架构师, 致力于研究 DDD, 分部式系统和其他 acronym-centric design/ 架构 / 方法论的研究. 同时也是 AutoMapper 的创始人和 ASP.NET MVC in Action 的作者

原文来自于 LosTechies.com.LosTechies 是一个公开的论坛,致力于通过一种公开且集中的途径分享技术见解和思维。并且希望所有人能够在思维讨论和借鉴中获得成就感和喜悦.

2. 译者简介

Let’s trrrans 翻译小组 (qq 群号:122783748) 一个致力于翻译和分享业界最前沿测试技术以及测试理念的翻译小组


感谢侯伯薇对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2014-05-27 04:035479

评论

发布
暂无评论
发现更多内容

湖仓一体电商项目(二十):业务实现之编写写入DM层业务代码

Lansonli

湖仓一体电商项目

大家心心念念的RocketMQ5.x入门手册来喽

中间件兴趣圈

RocketMQ rocketmq5

2023最新Python阅读书籍推荐

kcodez

Python

状态机设计举例

timerring

FPGA

New Bing 内测,革搜索的命

冯骐

openai GPT ChatGPT New Bing 对话模型

四点原因,Zoom裁员15%,视频会议甜蜜期结束

B Impact

免费的苹果手机投屏到电脑mac软件AIrserver7

茶色酒

AIrserver7

架构训练营 - 模块四作业

Sam

架构实战营

2023-02-11:给你两个整数 m 和 n 。构造一个 m x n 的网格,其中每个单元格最开始是白色, 请你用 红、绿、蓝 三种颜色为每个单元格涂色。所有单元格都需要被涂色, 涂色方案需要满足:

福大大架构师每日一题

算法 rust 福大大

springboot自动配置原理

喝水不抬头

软件测试/测试开发 | Web自动化之Selenium安装

测试人

软件测试 自动化测试 测试开发 Web自动化测试 selenium

软件测试/测试开发 | Web自动化之显式等待与隐式等待

测试人

软件测试 自动化测试 测试开发 web测试 web自动化

怎样做新人培训

Joseph295

极客时间架构训练营模块七-王者荣耀商城异地多活架构设计

张Dave

NodeJS 实战系列:DevOps 尚未解决的问题

光毅

DevOps nodejs

如何做总架构师

agnostic

总架构

软件测试/测试开发 | Selenium 测试用例编写

测试人

软件测试 自动化测试 测试开发 Web自动化测试 selenium

2023年金三银四必问的 1400 道 Java 面试题及答案整理,让你面试少走99%的弯路!

架构师之道

编程 程序员 java面试

软件测试/测试开发 | Web测试方法与技术之CSS讲解

测试人

软件测试 自动化测试 测试开发 Web自动化测试 web测试

ThreadLocal源码分析及避坑指南

喝水不抬头

软件测试/测试开发 | Web测试方法与技术实战演练

测试人

软件测试 自动化测试 测试开发 Web自动化测试

写给go开发者的gRPC教程-拦截器

凉凉的知识库

Go 微服务 gRPC http2

设计模式-值类型与引用类型、深拷贝与浅拷贝、原型模式详解

C++后台开发

数据结构 设计模式 后端开发 Linux服务器开发 C++开发

【SpringBoot】SpringBoot常用注解

No8g攻城狮

Spring Boot 2 #面试

运维训练营第十三课作业

好吃不贵

Python 发展趋势:与 Rust 深度融合、更易于编写 Web 应用

Python猫

Python

软件测试/测试开发 | SeleniumIDE用例录制

测试人

软件测试 自动化测试 测试开发 Web自动化测试 selenium

C++ 智能指针(一) std::auto_ptr

orbitgw

c++ C++ STL

被流量和热度裹挟,自媒体行业必须坚守职业道德

石头IT视角

开源ChatGPT要来了;软件2.0智能革命;GLM、Diffusion模型大加速

OneFlow

人工智能 深度学习

ChatGPT十问十答 | 图解ChatGPT

涛哥 数字产品和业务架构

人工智能 ChatGPT

一种有效的测试策略_语言 & 开发_Jimmy Bogard_InfoQ精选文章