简介
公司开发流程正规化一定会对单元测试有要求,写单元测试不仅可以在测试的过程中对程序单元的逻辑进行验证。还可以屏蔽外界依赖划清程序与程序之间的职责边界。
1.1 单元测试的特点
- 属于白盒测试
- 配合断言使用(杜绝System.out)
- 可重复执行
- 不依赖环境
- 不会对数据产生影响
- 可以和其他第三方系统划清边界
- Spring的上下文环境不是必须的
- 一般都要配合mock类框架来实现
1.2 mock类框架使用场景
要进行测试的方法存在外部依赖(如db, nacos,redis,第三方外部系统等),为了能够专注于对该方法(单元)的逻辑进行测试,就希望能虚拟出外部依赖,避免外部依赖成为测试的阻塞项,一般都是测试service层即可。
1.3 常用mock类框架
Mockito
1.4 如何引入Mockito框架
如果是SpringBoot项目只需要在pom.xml 加入这一个坐标即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
点开spring-boot-starter-test包可见这个starter里面包含三个关键的依赖
1.5 Mockito常用方法及注解
1.6 mock对象与spy对象
方法打桩 | 方法不打桩 | 作用对象 | 最佳实践 | |
---|---|---|---|---|
mock对象 | 执行插桩逻辑 | 返回mock对象的默认值 | 类、接口 | 被测试类或其依赖项 |
spy对象 | 执行插桩逻辑 | 调用真实方法 | 类、接口 | 被测试类 |
1.7 初始化mock/spy对象的方式
方法一 | 方法二 | 方法三 | |
---|---|---|---|
junit4 | @RunWith(MockitoJunitRunner.class) + @Mock等注解 | Mockito.mock(X.class) | MockitoAnnotations.openMocks(this) + @Mock等注解 |
junit5 | @ExtendWith(MockitoExtension.class) + @Mock等注解 | Mockito.mock(X.class) | MockitoAnnotations.openMocks(this) + @Mock等注解 |
1.8 方法插桩
指定调用某个方法时的行为(stubbing)达到相互隔离的目的
- 返回指定值
- void返回值方法插桩
- 插桩的两种方式
- when(obj.someMethod()).thenXxx(); // 其中obj可以是mock对象
- doXxx().when(obj).someMethod(); // 其中obj可以是mock/spy对象
- 抛异常
- 多次插桩
- thenAnswer
- 执行真正的原始方法
- verify的使用
1.9 @InjectMocks注解的使用
作用:若此注解声明的变量需要用到mock/spy对象,mockito会自动注入当前类里的mock或spy成员
原理:构造器注入、setter注入、字段反射注入
2.0 断言工具
- hamcrest
- assertj
- junit4原生断言
- junit5原生断言
2.1 mockito在springboot环境使用(不推荐)
生成的对象受spring管理,相当于自动替换对应类型bean的注入
@MockBean
类似@Mock
用于通过类型或名字替换spring容器中已经存在的bean,从而达到对这些bean进行mock的目的
@SpyBean
作用类似@Spy
用于通过类型或名字包装spring容器中已经存在的bean,当需要mock被测试类的某些方法是可以使用。
2.2 在IDEA中检查单元测试代码覆盖率
如果是红色的条状表示这些行的代码未被单元测试覆盖到
所以在写单元测试时为了保持较高的单元测试覆盖率,在写单元测试的时候需要考虑正例和反例多种情况,凡是在代码逻辑里面出现的多个逻辑分支都同样需要在单元测试用例中被考虑到,这样写出的单元测试不仅覆盖率高,而且代码质量也会很高。