一、算法单元测试遇到的一些问题
粒度和数据构造
现状
开发往往从大接口进行测试,即使有时从单元粒度进行测试,测试数据也构造不到位,导致单元测试形同虚设
建议
开发的单元测试应该以底层函数粒度为主,QA测试应该以中上层函数粒度为主。
整个单元测试流程:
(1)在设计评审和suffer测试结束并且编码接近尾声时,开发主动联系QA进行单元测试设计工作,QA此时已经拿到设计文档(注意:设计文档的粒度一定要包括基本功能模块的设计流程和输入输出数据等等),并且已经熟悉了设计和代码结构
(2)QA可以引导并和开发一起完成单元测试的功能点拆分、代码架构、单元测试TC设计评审(QA评审开发的单元测试TC,检查其是否对于逻辑覆盖全面,是否考虑异常情况等等),开发接着完成单元测试数据构造和编码,测试同步完成中上层接口的编码工作(注意:QA对于集成测试和接口测试应该更要考虑测试数据的各种组合情况、异常情况等,用例设计要完备)
(3)接着在codereview环节(注意:codereview并不是让开发给QA讲设计,而是要通过静态代码检查,review出代码中可能存在的编码缺陷、性能缺陷、设计缺陷等等)时,QA review开发的单元测试数据构造和编码并完善之(注意:QA不仅要review单元测试的编码结构,更要review测试数据的构造,检查其是否与之前的单元测试TC一致,并补充完善)
(4)随之进行的是TC总体评审,最后才进入测试执行环节
此流程的实施需要采用闭环机制,QA跟踪开发的执行情况,及时反馈存在的问题,闭环推进和改善。
可测性问题以及相关折中技术
现状
开发的代码结构不好,造成QA测试代码编码困难,例如难以剥离出清晰的功能点进行测试,或比较难构造清晰的测试数据
建议
算法开发更注重效果的实现,天然的对工程技术会有一定程度的不重视,所以在可测性上存在一定的缺陷。从开发的角度而言,可测性不好直接关系到单元测试的难以进行,也关系到项目本身的质量和以后的升级和维护。从QA的角度而言,算法架构不好导致功能点难以剥离出来进行测试,数据结构不好导致测试比较难构造清晰的测试数据,严重影响项目的测试工作。虽然QA可以通过一定的技术去弥补可测性上的问题,例如:mock技术(注意:mock技术还可以解决如对于一些第三方库函数返回不可预知情况的测试)、利用面向对象的继承机制、“曲线救国”方式等等,但是没有根本的解决问题,最好的方式还是提高代码的可测性。
二、单元测试代码的架构、编码和数据代码分离技术
单元测试的代码架构依赖于功能点的划分(功能点的划分是分层的)、整体代码的结构、数据的组织方式等等,测试代码也要讲究高可扩展性、高可维护性,所以应该做到层次化、模块化,这里主要由QA主导单元测试架构,由开发完成编码和优化。这里由开发编写基本测试用例,QA review,并补充用例。
数据结构易变的功能点
对于数据结构易变的功能点,采用数据和代码绑定的方式。基本上就是一份测试代码文件,输入和输出数据绑定在功能点的测试中,一个TEST_F完成一个功能点的测试,其中可能有多种输入TC。
对于数据结构相对稳定的功能点
采用数据和代码分离的方式。主要维护4份文件:输入TC、期望结果、测试配置——主要是一些字段配置、分层自动化测试代码,但一个TEST_F还是完成一个功能点的测试,测试数据对于功能点的区分由配置和测试数据文件中加入的一些注释来区分。
三、可测性方面以及折中的测试技术
可测性方面
良好的架构,尽量不要一个函数就1000行,做到低耦合、高内聚,高可扩展,函数封装明确、统一处理,充分利用面向对象机制的分类、继承、重载等做到层次分明,架构清晰,还有设计模式的使用,开放一些public的测试接口等等。另外,编写规范高效的makefile,添写合适的注释,打印日志等都有助于单元测试。
基于接缝技术的解耦合
预处理期接缝
顾名思义,就是通过宏来做一些手脚。通过编译前的预处理,达到我们的目的。
缺点:过度的使用宏只会降低代码的清晰性。如果因此引入宏相关的bug,定位的难度和成本会非常高。慎用!
连接期接缝
和mock比较类似,只是mock的对象是一个so,即替换链接的so。更确切的说,应该是fake。
缺点:如果环境没有理清楚的话,可能会导致一些环境上的问题。而且在正式的测试中,可能会导致环境混乱的情况。
对象接缝
面向对象语言中最为常见的一种接缝,一般可以通过继承的方式来实现(子类可以重载父类的方法)。
这是通过语言的特性实现的一种接缝方式,比较推荐这个方法。
另外,解决私有方法的测试问题的一个思路:
将private访问权限扩展为protected。将private扩大为protected,虽然访问权限是放大了一些,但总比public好多了。