测试是一个很古老的话题,几乎有了开发就有了测试。但是随着 DevOps 和敏捷的风潮之后,测试到底应该谁来做、需不需要独立的测试人员、测试到底应该关注什么,反而越来越模糊。至少在最近的几次周会和评审会上,发现大家在这些方面还是有很多的不明确和分歧。本文试图对说清楚白盒黑盒测试的区别,并对测试的分工和实施路径进行准确的阐述。
首先,我们先回到测试的目的上。软件测试的目的,和制造业测试的目的是一样的,就是验证交付物的质量。在制造业上,如果是无损的,可以对每件成本做测试;如果是有损的,采用抽样。对于软件来说,没有啥有损无损的区别,因为代码是可以无限复制的。同时,部署在不同机器的代码理论上也不会有什么太大的区别,可能环境因素会造成一定的差异。这里只需要在启动的时候加入轻量的自检流程即可。
软件的测试,主要还是集中在功能的验证上。在开发、集成、验收、发布阶段,都可能有不同角色参与的,视角不同的验收工作。
我们要验证交付物的质量,验证软件的功能是否正确,有两种方式去保证:白盒测试和黑盒测试。这两者的区别,我们可以拿买手机来举个例子。所谓的白盒测试,是我了解手机的各个组成,MPU 多少、GPU 多少、内存多少、屏幕分辨率多少、摄像头参数多少、基带芯片参数、操作系统是啥等等,然后一个个按照我自己要求的参数去做验证。黑盒,就是我对这些具体的内部结构和配置参数都不了解,我只知道我要拿手机来做什么,比如我要能用啥啥啥功能,玩什么游戏要到怎么一个流畅度、拍照片要达到什么效果,然后我拿这些功能一个个去试,符合要求的就是我要的。
软件测试也一样,白盒测试,就是按照我的设计说明书,按照包、类、方法、逻辑一层层往下拆解,验证实现是否符合设计的要求。所以白盒测试是在验证设计,不是验证功能。只做完白盒测试,有可能是一个设计优秀、运行稳定、性能良好、bug 很少但是没有用的垃圾。
而黑盒测试,是在验证功能。我不管你内部是怎么实现的,我也不管你内部的代码是不是写得优美,不管你的表结构设计是关系型的还是就一个大 json,甚至我不管你是 for 循环三次还是拆开来写了三次一样的代码,我只管功能是否被正确实现(特定的输入是否有符合预期的输出、用户交互是否符合产品设计、响应速度是否符合要求、用户使用上是否有障碍)。
举个具体的例子。比如我有一个下单功能,用户在界面上输入信息,确认后存储到数据库,然后回显到界面上,后续用户可以根据 orderId 反查询。
对于黑盒,我只下一个单,看一下回显,根据 orderId 查询一次,如果都符合设计要求,同时在性能和交互上也 ok,那就过了。
对于白盒,我的验证方式是将创建、查询拆开验证的。创建的时候需要验证输入的信息是否争取存储到数据库中,回显到时候需要验证对应 orderId 的 DB 数据是否正确被映射成对用户的输出。同时需要验证 orderId 不存在的情况是否正常的被处理。
比如我写代码的时候写了一个 bug:将 order 中的金额和数量两个字段落库的时候落反了,金额存在了数量里,数量存在了金额字段;查询的时候也是反着查的。这个时候,功能没有问题,黑盒测试是 pass 的。但是对于白盒测试,这个不符合设计,需要被定义成 bug。
白盒和黑盒测试是相辅相承的关系。如果要保证软件的质量,理论上其实只需要黑盒测试——保证交付物满足产品设计和用户的需求(包括功能和非功能)即可。但是,由于软件的复杂性,如果直接进行黑盒测试,往往失败的概率极大,而且也不容易定位问题所在。所以,按照分而治之的方式,先保证各个部分的质量,最后再来看整体产品的质量。而各部分的质量,首先需要满足设计的要求。而这个,采用白盒测试的方式比较更高效。所以,白盒测试满足各组件满足设计要求,最后再采用黑盒测试验收产品的整体交付质量。要保证大型软件交付的质量,白盒和黑盒测试缺一不可。
明白了黑盒和白盒测试的区别,我们也就明白了测试分工的原则。白盒测试是在验证设计和实现,还是属于开发的范畴,所以白盒测试应该由开发来完成。大部分的白盒测试,都是通过单元测试来 cover 的,平时也会构建 CI 来反复的验证。对于系统和系统之间的交互,基于服务契约解耦并通过契约测试来 cover:《契约测试的三种模式》。
而对于黑盒测试,这个是在验证产品的功能,最终需要是产品来做验证,如果是交互相关的可以由 UED 来验证。同时对于一些特殊的验证,比如性能、错误处理等,可以由专业的测试人员来负责。
在产品和 UED 验收之前,为了提升效率,可以增加一个端到端功能验证阶段,验收产品功能是否可以完整的跑起来、性能和稳定性如何。这个产品预验证阶段,可以交由独立的测试团队完成。
总之,我们可以将测试做如下划分:
白盒/单元测试:测试模块内的代码逻辑,开发负责。
白盒/契约测试:测试模块间的集成,开发负责。
黑盒/产品预验证:测试产品的功能连通性、性能、稳定性,测试负责。
黑盒/产品验收:测试产品的功能,产品负责。
黑盒/交互测试:测试用户交互体验,UED/产品负责。
安全测试:这个比较特殊,类似蓝军的攻击,专门的团队负责。
压力测试:专门团队负责。
基于上述的测试分工,我们也可以明确各类测试的实施路径:
单元测试和契约测试:在设计的时候进行测试分析,在编码阶段进行测试执行(编写用例)。
产品预验证:在产品阶段进行测试分析,在交付前进行测试执行。
产品验收、交互测试:在产品阶段进行测试分析,在交付前(交付给外部)或者交付后(交付后有验证阶段的)进行测试执行。
其他包括安全测试、压测等,可以按需进行。
最后,在人员构成上,由于开发需要负责设计编码和白盒测试,产品(包括 UED)需要负责产品设计和验收,测试负责产品预验证和稳定性保障。所以三部分人员的比例建议为 6:2:1。大头在开发,产品需要配齐,测试共享。
作者:agnostic
原文链接:https://xie.infoq.cn/article/8ec79e9224fdad8ea5c5b38da