前言:
为什么需要使用单元测试???
- 保证历史版本代码的正确性,减少重复测试:开发人员实现某个功能或者修补了某个bug,如果有相应的单元测试支持的话,开发人员可以马上通过运行单元测试来验证之前完成的代码是否正确;
- 提升测试效率:对于依赖多,业务流程复杂,可以通过mock去掉依赖,保证自己编写函数的正确性;
- 便于后期重构:保单元测试可以为代码的重构提供保障,只要重构代码之后单元测试全部运行通过,那么在很大程度上表示这次重构没有引入新的BUG,当然这是建立在完整、有效的单元测试覆盖率的基础上;
- 对设计的反馈:单元测试可以反过来指导设计出高内聚、低耦合的模块; 持续集成的一个前提,保证。
-- 下面中介绍Spring Boot项目中的单元测试
目录
Junit+SpringBootTest单元测试
Spring Boot中引入单元测试很简单,依赖如下:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-test'
}
引入spring-boot-starter-test后,有如下几个库:
•JUnit - 一个Java语言的单元测试框架。
•Spring Test&Spring Boot Test - 单元和用于系统的集成测试。
•AssertJ - 一个流畅的断言库。 •Hamcrest - matcher对象库(也称为约束或谓词),可以帮助我们创建匹配器对象。
•Mockito - 是一个针对Java的mocking框架。它与EasyMock和jMock很相似,但是通过在执行后校验什么已经被调用,它消除了对期望行为(expectations)的需要。
•JSONassert - JSON的断言库。 •JsonPath - 用于JSON的XPath。

Service层单元测试
创建测试类:
1、鼠标自动生成
Spring Boot中单元测试类写在在src/test/java目录下,你可以手动创建具体测试类,如果是IDEA,则可以通过IDEA自动创建测试类,如下图:

自动生成测试类如下:

2、Alt+Insert快捷键,选择Test...快速生成单元测试类
快速生成Junit单元测试技巧。
Alt+Insert呼出Generate界面,选择Test...,呼出右侧界面,其中①处可以选择单元测试所使用的框架或者二类库,②可以指定该类对应的单元测试类名称,③可以指定该单元测试类继承的父类,一般都是统一继承一个父类,父类里面写单元测试的注解、资源初始化、mock登录、资源释放等操作,④处指定生成的单元测试类包全路径,⑤处可以选择是否生成setUp和tearDown方法,一般③处继承父类就不需要勾选了,⑥处指定生成哪些方法的单元测试方法。


编写创建好的测试类,具体代码如下:
@RunWith(SpringRunner.class) // 表明执行程序用spring自己的执行机
@SpringBootTest //表明这是一个springboot测试类,会自动加载springboot主启动程序
public class GsCodeServiceImplTest {
@Autowired
GsCodeServiceImpl codeService;
@Test
public void add() {
GsCode gsCode = codeService.add("pages/visitresults/main?venueId=8ab3b87674d2655e0174d274572d0009",
1, "8ab3b87674d2655e0174d274572d0009");
Assert.assertNotNull(gsCode);
}
@Test
public void update() {
Optional<GsCode> optionalGsCode = codeService.findById("402882817511509201751150eaf00000");
GsCode code = optionalGsCode.get();
code.setCodeName("注册码更新");
GsCode updateCode = codeService.update(code,code.getId());
Assert.assertEquals(code.getCodeName(), updateCode.getCodeName());
}
@Test
public void findById() {
Optional<GsCode> optionalGsCode = codeService.findById("402882817511509201751150eaf00000");
Assert.assertNotNull(optionalGsCode.get());
}
@Test
public void list() {
List<Map<String, Object>> codeList = codeService.list(2);
Assert.assertNotNull(codeList.get(0));
}
@Test
public void pageList() {
Page<Map<String, Object>> pageList = codeService.pageList(1, PageRequest.of(0, 10));
Long items = pageList.getTotalElements();
assertThat(items, allOf(greaterThan(0L), lessThan(11L) ) );
}
@Test
public void delete() {
codeService.delete("402882817511509201751150eaf00000");
Optional<GsCode> optionalGsCode = codeService.findById("402882817511509201751150eaf00000");
Assert.assertNull(optionalGsCode.get());
}
@Test
public void findCodeListByIdList() {
List<String> codeList = new ArrayList();
codeList.add("8ab3b87674d2e0b70174d364a7610001");
List<Map<String, Object>> resultList = codeService.findCodeListByIdList(codeList);
Assert.assertSame(1, resultList.size());
}
}
上面就是最简单的单元测试写法,顶部只要@RunWith(SpringRunner.class))和 SpringBootTest即可,想要执行的时候,鼠标放在对应的方法,右键选择run该方法即可。 测试用例中我使用了assertThat断言,下文中会介绍,也推荐大家使用该断言。
Controller单元测试
上面只是针对Service层做测试,但是有时候需要对Controller层(API)做测试,这时候就得用到MockMvc了,可以不必启动工程就能测试这些接口。
MockMvc实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,这样可以使得测试速度快、不依赖网络环境,而且提供了一套验证的工具,这样可以使得请求的验证统一而且很方便。
Controller类:
package com.sncy.fuse.controller;
/**
* @author HJW
* @Description 二维码Controller
*/
@Slf4j
@RestController
@Api(tags = "二维码 接口")
@RequestMapping("gsCode")
public class GsCodeController {
@Autowired
IGsCodeService gsCodeService;
@GetMapping("/list")
@ApiOperation(value = "查询二维码信息列表,无分页", notes = "说明信息")
@ApiImplicitParam(name = "cType", dataType = "int", paramType = "query", value = "二维码类型", required = true)
public Result<List<Map<String, Object>>> list(@RequestParam int cType) {
try {
List<Map<String, Object>> codeInfoList = gsCodeService.list(cType);
log.info("查询二维码信息列表,无分页,codeInfoList:" + codeInfoList);
return new Result(ResultCode.CODE_OK.getValue(), ResultCode.CODE_OK.getDesc(), codeInfoList);
} catch (Exception e) {
log.error("查询二维码信息列表,无分页 异常!", e);
return new Result(ResultCode.CODE_Error_BUSINESS.getValue(), "操作失败,请稍后重试!", null);
}
}
@GetMapping("/pageList")
@ApiOperation(value = "查询二维码信息列表,有分页", notes = "说明信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "cType", dataType = "int", paramType = "query", value = "二维码类型", required = true),
@ApiImplicitParam(name = "pageNumber", dataType = "int", paramType = "query", value = "当前页数,从0开始", required = true),
@ApiImplicitParam(name = "pageSize", dataType = "int", paramType = "query", value = "每页条数", required = true)
})
public Result<Page<Map<String, Object>>> leaderPageList(int cType, Integer pageNumber, Integer pageSize) {
try {
Pageable pageable = PageRequest.of(pageNumber, pageSize);
Page<Map<String, Object>> pageList = gsCodeService.pageList(cType, pageable);
log.info("查询二维码信息列表,有分页,pageList:" + pageList);
return new Result(ResultCode.CODE_OK.getValue(), ResultCode.CODE_OK.getDesc(), pageList);
} catch (Exception e) {
log.error("查询二维码信息列表,有分页 异常!", e);
return new Result(ResultCode.CODE_Error_BUSINESS.getValue(), "操作失败,请稍后重试!", null);
}
}
@GetMapping("/downloadCode/{id}")
@ApiOperation(value = "下载二维码", notes = "说明信息")
@ApiImplicitParam(name = "id", dataType = "string", paramType = "query", value = "二维码id", required = true)
public Result downloadCode(HttpServletRequest request, HttpServletResponse response, @PathVariable String id) {
log.error("下载二维码! {}", id);
if (StringUtils.isBlank(id)) {

本文详细介绍SpringBoot项目中如何进行单元测试,包括Service层和服务接口的测试方法,并演示如何使用MockMvc进行Controller层的测试。
最低0.47元/天 解锁文章
452





