单元测试
SpringBoot 提供了 @SpringBootTest 注解,用于修饰单元测试用例类; 测试方法依然用 @Test 或 @ParameterizedTest 注解修饰
<!-- Spring Boot 单元测试的依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </denpendency>
其中 该依赖又依赖 JUnit 5.x, 所以会自动引入 JUnit 5的依赖,
一、 对控制器Controller 组件的测试
如下案例, 可以看到test成功,并且使用端口61358
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) //代表运行测试用例时随机端口; WebEnviroment.DEFIND_PORT 代表项目本身端口 @Slf4j public class ExecTest { @Autowired private TestRestTemplate restTemplate; @Test public void test01() { //测试test01 方法 String resp = restTemplate.getForObject("/test/test01",String.class); log.info("方法返回值:" + resp); Assertions.assertEquals("欢迎访问第一个 Spring Boot 应用", resp); } }
上面的测试案例中, 在运行单元测试时都会启动一个真实的 Web 服务器,如果不想启动真实的Web 服务器,可以使用 WebEnviroment.MOCK(默认为此配置) , 启动模拟服务器,
还可以获取ModelAndView 和常规返回值
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) @AutoConfigureMockMvc //启用MockMvc 的自动配置,Spring容器会自动配置一个 MockMvc Bean public class MockEnvTest { @Autowired private MockMvc mockMvc; //注入mockmvc bean @Test public void test01() throws Exception{ var resp = mockMvc.perform(MockMvcRequestBuilders.get(new URI("/test/test01"))).andReturn().getResponse().getContentAsString(); Assertions.assertEquals("欢迎访问第一个 Spring Boot 应用", resp); } @Test public void test02() throws Exception{ var resp = mockMvc.perform(MockMvcRequestBuilders.get(new URI("/test/test02"))).andReturn().getModelAndView(); // Assertions.assertEquals(Map.of("tip", "欢迎访问第一个 SpringBoot 应用"), resp.getModel()); Map.of 为jdk9 的快捷生成方法,目前jdk版本为8 Map map = new HashMap(); map.put("tip", "欢迎访问第一个 Spring Boot 应用"); Assertions.assertEquals(map, resp.getModel()); Assertions.assertEquals("hello", resp.getViewName()); } }
MockMvc 执行测试的方法只需要两步:
1、 使用MockMvcRequestBuilders 的 get()、post()、put()、patch()、delete()、options()、head() 等方法创建对应的请求, 如果需要设置请求参数、请求头等,则接着调用param()、header() 等方法
2、调用 MockMvc 对象的 perform() 方法执行请求; 返回值为 ResultActions, 可通过getResponse() 方法 或者 getModelAndView() 等获取到需要的响应
二、 测试业务组件
2.1 、 测试业务组件,不需要启动 web 服务器, 所以可将 WebEnviroment 属性设置为 WebEnviroment.NONE, 不启动web服务器
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) public class ServiceTest { @Autowired private TestService testService; @Test public void test01() { testService.getAllInfo().stream().forEach(System.out::println); } @ParameterizedTest @ValueSource(strings = {"张三"}) public void test01(String name) { System.out.println(testService.getScoreByName(name)); } }
2.2、 使用模拟组件
实际应用中,组件可能需要依赖其他的组件来访问数据库,或者调用第三方接口的服务,为了避免其他的因素影响单元测试效果,可以使用Mock 组件来模拟不稳定的组件,用于保证测试组件代码的健壮性; 如上面的 testService 组件实际使用testDao 来查询数据库,testDao可能尚未开发或者为测试通过,这时就需要我们先暂时模拟一个testDao.
@Test public void test03() { //模拟 TestDao 的getAllInfo() 方法的返回值 BDDMockito.given(this.testDao.getAllInfo()).willReturn( Arrays.asList("张三","李四") ); List<String> list = testService.getAllInfo(); Assertions.assertEquals(list.get(0), "张三"); Assertions.assertEquals(list.get(1), "李四"); }
注:后来遇到 springboot 2.1.8 版本还是需要配合添加 @RunWith(SpringRunner.class) 注解, 上述测试版本为 2.6.1 可直接使用 @SpringBootTest 即可。