Springboot单元测试

前言

在开发中,为了验证代码的可行性,会写测试单元去验证,执行单元测试,就是为了证明这 段代码的行为和我们期望是否一致

接口单元测试

1、Springboot2.4版本以上移除了junit4.x版本依赖,如果需要引入junit4.x版本的,请自行引入,maven仓库地址为: mvnrepository.com/artifact/ju...

2、Springboot高版本默认使用了junit5单元测试

junit5注解说明

注解 说明
@Test 表示方法是测试方法,但是与 JUnit4 的 @Test 不同,它的职责非常单一不能声明任何属性,拓展的测试将会由 Jupiter 提供额外测
@DisplayName 为测试类或者测试方法设置展示名称
@BeforeAll 表示在所有单元测试之前执行(被修饰的方法不必须是静态方法)
@BeforeEach 表示在每个单元测试之前执行
@Timeout 表示测试方法运行如果超过了指定时间将会返回错误
@Disabled 表示测试类或测试方法不执行
@RepeatedTest 表示方法可重复执行
@ExtendWith 为测试类或测试方法提供扩展类引用
@AfterEach 表示在每个单元测试之后执行
@AfterAll 表示在所有单元测试之后执行(被修饰的方法必须是静态方法)

单元测试编写

引入以下依赖

xml 复制代码
 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>

MockMvc使用

MockMvc是由spring-test包提供,实现了对Http请求的模拟,其实例化为

typescript 复制代码
       private MockMvc mockMvc;

	@Autowired
	private WebApplicationContext wac;

	@BeforeEach
	void setup() {
		this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
	}

测试单元编写

(1)先写一个接口

vbnet 复制代码
public class UserQuery {

    
    private Long id;


    private String account;


    private String username;

    private Long deptId;


    private List<Long> roleIds;
    
    private String password;
    

}
less 复制代码
  @PostMapping
    public R<Boolean> save(@RequestBody UserQuery userQuery) {
        log.info("保存数据为:{{}}", userQuery);
        return R.ok(null, "操作成功");
    }

再用测试单元对该接口进行测试

less 复制代码
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import cn.com.ut.utsmart.common.core.util.R;
import cn.com.ut.utsmart.light.query.user.UserQuery;
import cn.com.ut.utsmart.light.service.client.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@SpringBootTest
@DisplayName("UserController测试")
public class LightUserControllerTest {

	@MockBean
	UserService userService;

	@MockBean
	private RedisTemplate<String, String> redisTemplate;

	// @Autowired
	private MockMvc mockMvc;

	@Autowired
	private ObjectMapper objectMapper;

	@Autowired
	private WebApplicationContext wac;

	@BeforeEach
	void setup() {
		this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
	}

	@Nested
	@DisplayName("用户保存单元测试")

	public class UserAddTest {

		@Test
		@DisplayName("请求头合法,Method(POST),ContentType(application/json)) => HTTP_STATUS:200")
		public void save_1_test() throws Exception {
			UserQuery userQuery = new UserQuery();
			userQuery.setUsername("aa");
			userQuery.setDeptId(1L);
			userQuery.setAccount("aa");
			userQuery.setRoleIds(Collections.singletonList(1L));

			mockMvc
				.perform(post("/light/user").content(objectMapper.writeValueAsString(userQuery))
					.contentType("application/json"))
				.andExpect(status().isOk());
		}

		@Test
		@DisplayName("请求不合法,Method(Get) => HTTP_STATUS:405")
		public void save_2_test() throws Exception {
			UserQuery userQuery = new UserQuery();
			userQuery.setUsername("aa");
			userQuery.setDeptId(1L);
			userQuery.setAccount("aa");
			userQuery.setRoleIds(Collections.singletonList(1L));

			mockMvc
				.perform(get("/light/user").content(objectMapper.writeValueAsString(userQuery))
					.contentType("application/json"))
				.andExpect(status().is(HttpStatus.METHOD_NOT_ALLOWED.value()));
		}

		@Test
		@DisplayName("请求内容不合法,调用service.save()失败 => 返回失败")
		public void save_3_test() throws Exception {
			UserQuery userQuery = new UserQuery();
			userQuery.setUsername("aa");
			userQuery.setAccount("aa");
			userQuery.setRoleIds(Collections.singletonList(1L));
			when(userService.save(userQuery)).thenReturn(false);

			// when
			MvcResult mvcResult = mockMvc
				.perform(post("/light/user").content(objectMapper.writeValueAsString(userQuery))
					.contentType("application/json"))
				.andExpect(status().isOk())
				.andReturn();

			// then
			String actualRespBody = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
			String expectRespBody = objectMapper.writeValueAsString(R.ok(false, "操作成功"));
			assertThat(actualRespBody).isEqualToIgnoringCase(expectRespBody);
			verify(userService, times(1)).save(Mockito.any(UserQuery.class));
		}

		@Test
		@DisplayName("请求内容合法,调用service.save()成功 => 返回成功")
		public void save_4_test() throws Exception {
			UserQuery userQuery = new UserQuery();
			userQuery.setUsername("aa");
			userQuery.setAccount("aa");
			userQuery.setRoleIds(Collections.singletonList(1L));
			when(userService.save(userQuery)).thenReturn(true);
			// when
			MvcResult mvcResult = mockMvc
				.perform(post("/light/user").content(objectMapper.writeValueAsString(userQuery))
					.contentType("application/json"))
				.andExpect(status().isOk())
				.andReturn();
			// then
			String actualRespBody = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
			String expectRespBody = objectMapper.writeValueAsString(R.ok(true, "操作成功"));
			assertThat(actualRespBody).isEqualToIgnoringCase(expectRespBody);

			verify(userService, times(1)).save(userQuery);
		}

		@Test
		@DisplayName("参数认证不合法,账号为空,Method(POST),ContentType(application/json)) => HTTP_STATUS:400")
		public void save_5_test() throws Exception {
			UserQuery userQuery = new UserQuery();
			userQuery.setUsername("aa");
			userQuery.setDeptId(1L);
			userQuery.setRoleIds(Collections.singletonList(1L));

			MvcResult mvcResult = mockMvc
				.perform(post("/light/user").content(objectMapper.writeValueAsString(userQuery))
					.contentType("application/json"))
				.andExpect(status().is(HttpStatus.BAD_REQUEST.value()))
				.andReturn();
			String actualRespBody = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
			String expectRespBody = objectMapper.writeValueAsString(R.failed("账号不能为空"));
			assertThat(actualRespBody).isEqualToIgnoringCase(expectRespBody);
		}

	}

}

assertThat使用

assertThat是junit4.4的一个新断言语句,结合 Hamcrest 提供的匹配符,可以用来匹配值是否与期望一致

less 复制代码
@SpringBootTest
@DisplayName("测试")
public class HelloTest {

	@Test
	public void hello() {
		String data = "aaa";
		assertThat(data).isEqualTo("aaa");
	}

}

总结

在写方法或者接口过程中,我们可以根据测试用例,写对应的单元测试去测试接口或者方法是否符合预期

相关推荐
骑士雄师8 分钟前
Java 泛型中级面试题及答案
java·开发语言·面试
Victor35610 分钟前
Redis(61)Redis的连接数上限是多少?
后端
Victor35614 分钟前
Redis(60) Redis的复制延迟如何优化?
后端
.格子衫.6 小时前
Spring Boot 原理篇
java·spring boot·后端
多云几多6 小时前
Yudao单体项目 springboot Admin安全验证开启
java·spring boot·spring·springbootadmin
Jabes.yang8 小时前
Java求职面试实战:从Spring Boot到微服务架构的技术探讨
java·数据库·spring boot·微服务·面试·消息队列·互联网大厂
聪明的笨猪猪8 小时前
Java Redis “高可用 — 主从复制”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
兮动人8 小时前
Spring Bean耗时分析工具
java·后端·spring·bean耗时分析工具
MESSIR229 小时前
Spring IOC(控制反转)中常用注解
java·spring
摇滚侠9 小时前
Spring Boot 3零基础教程,Demo小结,笔记04
java·spring boot·笔记