赞
踩
目录
单元测试通常的没有一个良好的通用规范,因此本文在阅读大量文章资料的基础上结合开发中自己的心得体会总结出一版单元测试的规范和指南。
开发阶段 = 逻辑代码开发 + 编写单测用例
误区:提测时或者上线前才开始写测试用例
1.结果是否正确
看程序运行之后的结构和文档是否一致。当然可能很多的时候一个方法没有很完整的文档描述它,那至少也应该有简单的文字描述,否则没有判断是否正确的依据。一个原则是:对于验证被测方法是否正确的这件事情,如果某些做法能够使它变得更加容易,那么就采纳它。
2.边界条件CORRECT
很多bug都会集中在边界附近,所以应该多注意。
3.检查反向关联
对于一些方法,我们可以使用反向的逻辑关系来验证它们。注意当同时编写了原方法和它的反向测试时,一些bug可能会被在两个函数中都出现的错误所掩盖。在可能的情况下,应该使用不同的原理来编写反向测试。
4.使用其他手段来实现交叉检查
通常解决一个问题会有多种手段,如果你选择了其中一个方法,那么就可以用其它的方法来检验它。另一种方法就是:使用类本身不同组成部分的数据,并且确信它们能“合起来”。
5.强制产生错误条件
应当能够通过强制引发错误,来测试代码是如何处理所有这些真实问题的。
下面是一些常见环境方面的因素:
6.性能特性
一个检查起来会很有益处的部分是性能特性,而不是性能本身。
代码编写完成后的单元测试工作主要分为两个步骤:
5.1 人工静态检查
人工静态检查是测试的第一步,这个阶段工作主要是保证代码算法的逻辑正确性(尽量通过人工检查发现代码的逻辑错误)、清晰性、规范性、一致性、算法高效性。并尽可能的发现程序中没有发现的错误。
通常在人工检查阶段必须执行以下项目的活动:
5.2 动态执行跟踪
执行待测程序来跟踪比较实际结果与预期结果来发现错误。经验表明,使用人工静态检查法能够有效的发现30%到70%的逻辑设计和 编码错误。但是代码中仍会有大量的隐性错误无法通过视觉检查发现,必须通过跟踪调试法细心分析才能够捕捉到。所以,动态跟踪调试方法也成了单元测试的重点与难点
⼀般一个三步经典结构:准备,调⽤,断⾔。
在做单元测试的时候,我们会发现我们要测试的方法会引用很多外部依赖的对象,如调用平台接口、连接数据库、网络通讯、远程服务、FTP、文件系统等等。 而我们没法控制这些外部依赖的对象,为了解决这个问题,我们就需要用到Mock工具来模拟这些外部依赖的对象,来完成单元测试。
现在比较流行的Mock工具有JMock、EasyMock、Mockito、PowerMock。
推荐使用的是Mockito和PowerMock。PowerMock弥补了其他3个Mock工具不能mock静态、final 、私有方法的缺点。
当用例出现下面的情况我们可以使用Mock对象来完成单元测试:
具体Mockito和PowerMock用法可以参考 工作多年后我更体会到单元测试的重要性
1、test包结构包名必须同main一致
2、对应类的单元测试类命名:${className}Test,
eg: main:com.hellobike.ride.application.RideIfaceImpl ===> test:com.hellobike.ride.application.RideIfaceImplTest
如下图:
单元测试方法命名:test${MethodName}${Scene},以驼峰形式命名
eg:reserve ===> testReserveSuccess、testReserveOverTimes、testReserveInvalidParams
如下图:
1. 【强制】好的单元测试必须遵守 AIR 原则。
说明: 单元测试在线上运行时,感觉像空气(AIR)一样并不存在,但在测试质量的保障上, 却是非常关键的。好的单元测试宏观上来说,具有自动化、独立性、可重复执行的特点。
2. 【强制】单元测试应该是全自动执行的,并且非交互式的。测试框架通常是定期执行的,执行过程必须完全自动化才有意义。输出结果需要人工检查的测试不是一个好的单元测试。单元测试中不准使用 System.out 来进行人肉验证,必须使用 assert 来验证。
3. 【强制】保持单元测试的独立性。为了保证单元测试稳定可靠且便于维护,单元测试用例之间绝对不能互相调用,也不能依赖执行的先后次序。
反例: method2 需要依赖 method1 的执行,将执行结果做为 method2 的输入。
4. 【强制】单元测试是可以重复执行的,不能受到外界环境的影响。
说明: 单元测试通常会被放到持续集成中,每次有代码check in时单元测试都会被执行。如果单测对外部环境(网络、服务、中间件等)有依赖,容易导致持续集成机制的不可用。
正例: 为了不受外界环境影响,要求设计代码时就把 SUT 的依赖改成注入,在测试时用 spring这样的 DI 框架注入一个本地(内存)实现或者 Mock 实现。
5. 【强制】对于单元测试,要保证测试粒度足够小,有助于精确定位问题。单测粒度至多是类级别,一般是方法级别。
说明: 只有测试粒度小才能在出错时尽快定位到出错位置。单测不负责检查跨类或者跨系统的交互逻辑,那是集成测试的领域。
6. 【强制】核心业务、核心应用、核心模块的增量代码确保单元测试通过。
说明: 新增代码及时补充单元测试,如果新增代码影响了原有单元测试,请及时修正。
7. 【强制】单元测试代码必须写在如下工程目录:src/test/java,不允许写在业务代码目录下。
说明: 源码构建时会跳过此目录,而单元测试框架默认是扫描此目录。
8. 【推荐】单元测试的基本目标:语句覆盖率达到 70%;核心模块的语句覆盖率和分支覆盖率都要达到 100%
说明: 在工程规约的应用分层中提到的 DAO 层,Manager 层,可重用度高的 Service,都应该进行单元测试。
9. 【推荐】编写单元测试代码遵守 BCDE 原则,以保证被测试模块的交付质量。
10. 【推荐】对于数据库相关的查询,更新,删除等操作,不能假设数据库里的数据是存在的, 或者直接操作数据库把数据插入进去,请使用程序插入或者导入数据的方式来准备数据。
反例: 删除某一行数据的单元测试,在数据库中,先直接手动增加一行作为删除目标,但是这 一行新增数据并不符合业务插入规则,导致测试结果异常。
11. 【推荐】和数据库相关的单元测试,可以设定自动回滚机制,不给数据库造成脏数据。或者 对单元测试产生的数据有明确的前后缀标识。
正例:在 RDC 内部单元测试中,使用 RDC_UNIT_TEST_的前缀标识数据。
12. 【推荐】对于不可测的代码建议做必要的重构,使代码变得可测,避免为了达到测试要求而 书写不规范测试代码。
13. 【推荐】在设计评审阶段,开发人员需要和测试人员一起确定单元测试范围,单元测试最好 覆盖所有测试用例(UC)。
14. 【推荐】单元测试作为一种质量保障手段,不建议项目发布后补充单元测试用例,建议在项 目提测前完成单元测试。
15. 【参考】为了更方便地进行单元测试,业务代码应避免以下情况:
说明: 多层条件语句建议使用卫语句、策略模式、状态模式等方式重构。
16. 【参考】不要对单元测试存在如下误解:
单元测试覆盖目标增量覆盖70%,全量覆盖50%,若覆盖度未达到,atlas研发平台将拒绝相关分支代码发布。
Squaretest,是一款IDEA插件,基于Velocity模板生成单测,会帮每个对应的被测方法生成一个测试类,spring的注入类会被mock掉,没有参数推导,所以参数还需要用户自行填充。
1、IDEA安装插件“Squaretest”,如下图:
2、打开需要被单测覆盖的类,然后右键,点击“Generate…”(中文为生成)
3、点击“Generate Test - Confirm Mocks”,如下图:
4、然后选中需要mock的属性,点击ok。即自动在test包下面生成单元测试。
5、需要被单测的类中的自动注入全部由Mock产生。内容如下图:
原始类:
自动生成单测类:
6.运行结果:
原始类方法中会有filter方法,因此单测时可以分为是否有过滤两种情况。
有过滤情况:
运行结果:
无过滤情况:
运行结果:
方法覆盖率:
Diffblue 是一款基于AI来编写单测的工具,它分析现有的Java应用程序,并编写反映当前行为的单元测试,从而增加测试范围并帮助您在将来的代码更改中查找回归。Cover在代码更改时通过更新测试来自动维护测试。Cover支持标准Java 8和11,Spring和Spring Boot,但是需要springboot 2.x起。
1.IDEA安装插件“DiffBlue”,如下图:
2.点击左侧图标或右键生成
3.自动生成测试类
注意:不是很稳定,可能出现错误,需要程序员自己修改
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。