单元测试理论知识
什么是单元测试?
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。通常而言,一个单元可能是单个程序、类、对象、方法等。
为什么需要单元测试
为什么要做单元测试?软件中存在的错误发现得越早,修改和维护的费用就越低,难度也越小。单元测试是在软件开发验证过程的底层和早期进行的测试活动,目的是把缺陷消灭在萌芽状态。
单元测试有什么作用?
-
实现敏捷开发,单元测试的主要好处之一是它使编码过程更加敏捷。当软件中添加越来越多的功能时,有时需要更改旧的设计和代码,但是更改已测试的代码既有风险又耗费时间。如果有单元测试,则有助于安全重构。
-
提高代码质量,由于单元测试是在集成测试之前对最小可测单元的测试,所以能够尽早的发现软件代码中的缺陷,并在不影响其他代码部分的情况下解决问题。这些问题包括程序实现中的错误和单元规范中的缺陷及缺失。通过代码检查和已有缺陷的完善,代码质量可以得到大幅度提高。
-
消除深度未知隐患,软件开发天生就具有极大的复杂性,没人能100%保证自己写出来的程序没有问题。开发中的初步功能验证我们会用仿真,或模型及代码调试技巧进行结果值确认,这种测试一般只能覆盖部分执行路径,未覆盖执行路径就留下了很多未知隐患。为了保证我们的程序在各种情况下都能按照预设响应,就需要对我们的模型或者代码进行严格的基于需求的测试和覆盖率测试(俗称:白盒测试),而这种测试只能在单元测试中进行。
-
优化设计和架构,单元测试可以辅助优化设计和架构,比如通过处理器在环(Processor In the Loop)来评估最长执行时间(WCET),内存和堆栈使用量,优化设计和架构,尽早地回避集成后的执行时间及内存的溢出问题
-
满足行业规范要求,满足Automotive SPICE过程及ISO26262安全规范对单元测试的要求,以从第三方认证公司获取相关认证证书。
什么时候单元测试?
单元测试越早越好,早到什么程度?极限编程讲究TDD,即测试驱动开发,先编写测试代码,再进行开发。在实际的工作中,可以不必过分强调先什么后什么,重要的是高效性和实用性。从经验来看,对于单元测试可以先编写产品函数的框架、编写测试函数,再针对产品函数的功能编写测试用例,然后编写产品函数的代码。在实际编码过程中,每写一个功能点就进行相应的测试,并且随时补充测试用例
常见单元测试框架
TestNG vs Junit4
Testng支持分组测试 Testng参数化测试支持复杂类型参数,而junit只支持基本类型 Testng支持依赖测试
Testng提供XML灵活配置测试运行套件
执行流程
单元测试框架使用
预期异常测试
当期望被测代码抛出一个异常,可以通过在 @Test 注解后加入预期的 Exception 来进行添加。
忽略测试
当期望被测代码抛出一个异常,可以通过在 @Test 注解后加入预期的 Exception 来进行添加。
超时测试
参数化测试
多数情况下,会遇到业务逻辑需要大量测试的场景。 参数化测试允许开发人员使用不同的参数值多次运行相同的测试。注解@Parameters返回数组的集合。每个数组包括每个测试执行输入/输出数字。每个数组中的元素数必须和构造参数的数目相同
@DataProvider当需要传递复杂的参数(列表、对象…),在这种情况下,可以使用数@DataProvider注解。
被@Test标注的方法通过dataProvider属性指明其数据提供者。这个名字需与@DataProvider(name=“…”)中的名字相一致。
对象作为参数:
依赖测试(TestNG)
有时,我们可能需要以特定顺序调用测试用例中的方法,或者可能希望在方法之间共享一些数据和状态。
使用dependOnMethods和dependsOnGroups来实现依赖测试。 如果依赖方法失败,则将跳过所有后续测试方法
Mock测试
在做单元测试的时候,有时候我们要测试的方法会有很多外部依赖的对象或者一些其他服务的调用。 而我们没法控制这些外部依赖的对象。
为了解决这个问题,我们需要用到 Mock 来模拟这些外部依赖的对象,从而控制它们。只需要关心我们自己的业务逻辑是否正确。
当我们需要测试 UserService 服务时,如果构建真实的 userDao, DB, xxxService、RPC实例, 然后注入到 UserService 中,既笨重又繁琐。 Mock 对象后的框架图
UserDao, xxxService 和 RPC 都被我们使用了虚拟的对象(Mock 对象) 来替换了, 因此我们就可以对 UserService 进行测试, 而不需要关注它的复杂的依赖了.
Mock框架
地址:https://javadoc.io/static/org.mockito/mockito-core/4.8.1/org/mockito/Mockito.html
一些常用的 mock 库包括 Mockito、JMockIt、EasyMock、PowerMock…没有优劣没有好坏,只有合适与否。
Mockito可以对普通的方法进行Mock,如:public等。PowerMock可以实现完成对private/static/final方法的Mock
Mockito 是一个强大的用于 Java 开发的模拟测试框架, 通过 Mockito 我们可以创建和配置 Mock 对象, 进而简化有外部依赖的类的测试。Mockito对比其他Mock框架:
-
相对于其他几个老牌框架来说比较新并且应用更广泛。
-
相对于其他几个老牌框架来说比较新并且应用更广泛。
-
编码设计简洁优美,使用简单快捷,成本低。
抽象出测试中的经典概念,如when().thenReturn()、doThrow().when()、verify()、times()、never()以及各种注解很容易理解
Mockito框架
使用 Mockito 的大致流程如下:
- 创建外部依赖的 Mock 对象, 然后将此 Mock 对象注入到测试类中。
- 执行测试代码.
- 校验测试代码是否执行正确。
常见单元测试插件
squaretest
TestMe
https://weirddev.com/testme/