关于单元测试与集成测试
- 单元测试:针对代码中最小可测试单元进行测试,通常就是一个方法块。单元测试只关注方法本身的业务逻辑,
不关心其余任何与外部交互的方法或接口。 - 集成测试:在单元测试的基础上将所有模块按照系统设计或业务规则组装为子系统或系统。
集成测试主要目的是验证各个模块之间能否顺利交互,比如第三方API能否调通。
Mockito
单元测试的基本流程:
- 模拟并替换测试代码中所有的外部依赖及行为
- 执行被测方法
- 验证方法执行结果
- 验证异常捕获结果
快速上手
-
使用
@RunWith(MockitoJUnitRunner.class)
注解或MockitoAnnotations.initMocks(this)
语句(放在setUp中)实例化mock对象 -
需要mock的外部依赖使用
@Mock
注解声明,例如:@Mock private BlockVolumeBackupService blockVolumeBackupService;
-
模拟方法行为
Mockito.when(mockObject.method()).thenReturn(object)
-
模拟异常
Mockito.when(mockObject.method()).thenThrow(Exception)
-
模拟void方法
Mockito.doNothing().when(mockObject).someVoidMethod()
-
对结果进行断言
Assert.assertEquals(actural, except)
Controller层的mock
- 使用
MockMvc
框架 - 初始化MockMvc
mvc = MockMvcBuilders.standaloneSetup(cinderRestV3Controller).build();
- 模拟请求并断言返回值
mvc.perform(delete("/ebs/v1/volumes/1/soft") .header(AUTHORIZATION, "2").content("3")) .andExpect(status().isOk()) .andExpect(content().json("{\"code\":\"202\",\"message\":null,\"data\":null}"));
注意点
Mockito
无法mockstatic
private
方法,需要使用PowerMockito
框架,添加@PrepareForTest
注解并且在setUp
方法中声明PowerMockito.mockStatic(Base64Util.class)
- 异常测试有两种方式,一种是通过Junit的
@Rule
注解,一种是通过try..catch
然后断言的方式。@Rule
方式更简洁,但如果要在一个测试方法中连续测试多个抛出的异常只能使用第二种方式,因为@Rule
方式在异常抛出之后程序就终止了,无法继续进行 - 多次mock时务必注意先后顺序。上文的mock结果会在下一次mock时仍然生效。比如先
when(method.getList()).thenReturn(null)
之后,又继续写when(method.getList().get(0)).thenReturn("abc")
会导致NPE - Controller层单元测试不需要启动应用,也就不需要给类名加任何Test相关的注解
- 注意import相关包的方式,有些人喜欢以static的方式引入,在网上参考他人代码时务必注意一下
- mock方法行为时,需注意调用时的url请求参数应该与mock时的参数保持一致,否则mock不成功。(若使用AnyString()等方法mock可无视此条)
- A类中依赖注入了B类,在写A的测试类时要注意:对A使用
@InjectMocks
注解,对于B使用@Mock
注解