最近项目组开始重视单元测试,自己很想加强自己单元测试。之前在写单元测试最大阻碍就是启动整个上下文,单元测试时间太长。最近看了一些资料与实践,缩短了单测时间,留下笔记与大家分享
优化前后做法对比 优化前@RunWith(SpringRunner.class)
@SpringBootTest(classes = ClientApplication.class)
@ActiveProfiles("fat")
public class DiffTest {
@Resource
private TaskAliEventCallbackCoreMapper taskAliEventCallbackCoreMapper;
@Test
public void testDiff(){
TaskAliEventCallbackEnt taskAliEventCallbackEnt = taskAliEventCallbackCoreMapper.getByOrderIdAndEventCode(10270686L,1);
System.out.println(taskAliEventCallbackEnt.getReferenceNo());
}
}
- ClientApplication是整个应用的启动入口,这就说明你启动测试类需要加载的Bean的数量和正常启动加载的Bean的数量是一样的
- 如果你的项目中有很多个 Bean, 有些Bean需要加载初始化数据,从而延后了测试方法的运行
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {AliApiAction.class,AliOrderAddService.class},
webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class AliApiActionTest {
@MockBean
private AliOrderCancelService aliOrderCancelService;
@MockBean
private AliOrderPayService aliOrderPayService;
@MockBean
private AliOrderDao aliOrderDao;
@Resource
private AliApiAction apiAction;
@Test
public void testException() throws JAXBException {
String dataBody = "asdasda";
Map valiBackMap = new HashMap<>();
valiBackMap.put(WebCst.MSG,WebCst.SUCCESS);
given(aliOrderDao.valiOrderForecast(dataBody)).willReturn(valiBackMap);
doThrow(new JAXBException("测试")).when(aliOrderDao).addAliOrderForecast(dataBody);
String result = apiAction.main("orderForecast",dataBody,"11ACE1D0F1C5F11954405C5566BBA3A203501B43");
System.out.println(result);
}
}
- AliApiAction为要测试Controller入口
1.1 AliOrderAddService为AliApiAction依赖的service,待测的service
(1)AliOrderDao是AliOrderAddService依赖的持久层,按条件Mock掉
1.2 AliOrderCancelService、AliOrderPayService也是AliOrderAddService依赖的service,但不需要测,直接Mock掉 - 这样只加载指定的Bean,单测时间大大减少,非常的nice
2.1.16.RELEASE版本的官方文档
- spring-boot-starter-test包含一下提供的库
1.1 Junit4: 单元测试库
1.2 Spring Test与Spring Boot Test:对SpringBoot应用程序的集成测试支持
1.3 AssertJ:断言库
1.4 Hamcrest:匹配器对象库(也称为约束或谓词)
1.5 Mockito:Java模拟框架
1.6 JSONassert:JSON 的断言库
1.7 JsonPath : JSON 的 XPath
-
Spring Boot包含一个@MockBean注解,可用于在ApplicationContext中为bean定义Mockito mock
1.1 @SpringBootTest会自动启用该特性
1.2 要以不同的方式使用该特性,必须显示添加监听器(如@TestExecutionListeners (MockitoTestExecutionListener.class))@RunWith(SpringRunner.class) @SpringBootTest public class MyTests { @MockBean private RemoteService remoteService; @Autowired private Reverser reverser; @Test public void exampleTest() { // RemoteService has been injected into the reverser bean given(this.remoteService.someCall()).willReturn("mock"); String reverse = reverser.reverseSomeCall(); assertThat(reverse).isEqualTo("kcom"); } } -
@MockBean不能用于模拟在应用程序上下文刷新期间执行的bean的行为
2.1 在执行测试时,应用程序上下文刷新已经完成
2.2 在这种情况下,我们建议使用@Bean方法来创建和配置模拟 -
可以使用@SpyBean将任何现有bean包装为Mockito spy,请参阅Javadoc
- spring-boot-test官网:https://docs.spring.io/spring-boot/docs/2.1.16.RELEASE/reference/html/boot-features-testing.html
- 单元测试示例spring-boot-testing-strategies



