大家好,我是神韵,是一个技术&生活博主。出文章目的主要是两个,一是好记忆不如烂笔头,记录总结中提高自己。二是希望我的文章可以帮到大家。欢迎来点赞打卡,你们的行动将是我无限的动力。
本篇主题是:编写第一个单元测试
其它文章链接:
Unit Test 1–什么是单元测试
Unit Test 2–IDEA配置并查看单元覆盖率
Unit Test 3–编写单元测试之前需要了解的单元测试框架Mock
Unit Test 4–自动生成单元测试插件之TestMe与Diffblue
Unit Test 6–单元测试踩过的坑
Unit Test 7–单元测试覆盖率表单生成交付,Jacoco的使用
Controller 层的单元测试怎么写?
同一个类的方法怎么Mock?spy函数啦
上一篇文章介绍了两个插件,1是Diffbule,2是TestMe,如果用第一款插件可以省事很多。本篇文章主要是介绍单元测试编写,一般建议通过插件生成后再自己进行修改即可。
项目所需依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.9.0</version>
</dependency>
</dependencies>
1、controller层 Unit Test
2021/11/24 add - 最新参考:Controller 层的单元测试怎么写?
因为如果通过MVC是比较复杂的,但是应该是最正确的方式,但是上面链接的也可以,简单快捷。
需要编写单元测试的类UnitTestController.java
@RestController
public class UnitTestController {
@Autowired
private UnitTestService unitTestService;
@PostMapping("/unitTest")
public UnitTestRspDTO unitTest(@RequestBody UnitTestReqDTO unitTestReqDTO) {
UnitTestEntity unitTestEntity = unitTestService.queryUnitTestByContent(new UnitTestEntity(unitTestReqDTO.getId(), unitTestReqDTO.getContent()));
UnitTestRspDTO unitTestRspDTO = new UnitTestRspDTO();
unitTestRspDTO.setId(unitTestEntity.getId());
unitTestEntity.setContent(unitTestEntity.getContent());
return unitTestRspDTO;
}
}
1、Controller层需要通过Mvc去调用,这个类上需要指定加载测试类的容器(controller特有,后面需要Mock Mvc)
2、之前文章提到过,编写单元测试几步走
-
准备测试数据 (重)
-
Mock需要的对象,Mock具体行为
需要注入对象MockMvc,通过Mvc调用URL(controller特有)
Mock 业务类,本来是真实注入业务类UnitService,这里去模拟一个它然后去模拟行为
Mock具体行为,返回第一步制造的数据
-
构建请求数据
post调用/json传参
ps:如果真实代码没有里面没有用到传入的参数,也可以用"{}"来传
ps:如果是get方法如下
-
做真实调用需要测试的方法调用并比对结果
至此一个controller测试案例到此结束
完整代码
@RunWith(SpringRunner.class)
@WebMvcTest(UnitTestController.class)
public class UnitTestControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UnitTestService unitTestService;
@Test
public void testUnitTest() throws Exception {
// mock行为
when(unitTestService.queryUnitTestByContent(any())).thenReturn(getUnitTestEntity());
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/unitTest")
.contentType(MediaType.APPLICATION_JSON) // 参数接收类型,json
.content(new ObjectMapper().writeValueAsString(getUnitTestEntity())); // 参数内容 json
mockMvc.perform(requestBuilder).andExpect(status().isOk()); // 响应验证
}
// 测试数据
private UnitTestEntity getUnitTestEntity() {
return new UnitTestEntity(1, "test");
}
}
2、Service层 Unit Test
service层不像controller需要从URL入手,这个就简单很多~~
需要编写单元测试的类UnitTestService.java
@Service
public class UnitTestService {
@Autowired
private UnitTestRepository unitTestRepository;
public UnitTestEntity queryUnitTestByContent(UnitTestEntity unitTestEntity) {
return unitTestRepository.findByContent(unitTestEntity.getContent());
}
}
- 准备测试数据
2、Mock对象及行为
对于本身类,需要做调用的通过@InjectMocks去Mock
这里Mock 其他类没用MockBean,因为没有类上没有启用容器(如WebMvcTest/SpringBootTest…),MockBean会失败~~
3、做真实代码调用
4、对比结果
完整代码:
@RunWith(MockitoJUnitRunner.class)
public class UnitTestServiceTest {
@InjectMocks
private UnitTestService unitTestService;
@Mock
private UnitTestRepository unitTestRepository;
@Test
public void testQueryUnitTestByContent() {
// 模拟行为--unitTestRepository.findAll(),并指定返回自己想要的结果
Mockito.when(unitTestRepository.findByContent(any())).thenReturn(getUnitTestEntity());
// 调用service方法
UnitTestEntity unitTestEntity = unitTestService.queryUnitTestByContent(getUnitTestEntity());
// 校验结果
Assert.assertEquals(getUnitTestEntity().getId(), unitTestEntity.getId());
}
// 制造一个返回结果
private UnitTestEntity getUnitTestEntity() {
return new UnitTestEntity(1, "test");
}
}
3、Dao层
这里我们使用的是JPA,没有用到这一层的单元测试,略…
4、测试结果
好,现在我们来运行一下单元测试案例,看下我们编写了两个测试类的效果,具体前面怎么配置和运行已经写过文章
结果如下:
controller/service覆盖率为100%~