SpringBoot单元测试进阶:Mockito+JUnit5的23种测试场景
·
🎓博主介绍:Java、Python、js全栈开发 “多面手”,精通多种编程语言和技术,痴迷于人工智能领域。秉持着对技术的热爱与执着,持续探索创新,愿在此分享交流和学习,与大家共进步。
📖DeepSeek-行业融合之万象视界(附实战案例详解100+)
📖全栈开发环境搭建运行攻略:多语言一站式指南(环境搭建+运行+调试+发布+保姆级详解)
👉感兴趣的可以先收藏起来,希望帮助更多的人
SpringBoot单元测试进阶:Mockito+JUnit5的23种测试场景
一、引言
在软件开发过程中,单元测试是保证代码质量、提高开发效率的重要手段。Spring Boot作为目前流行的Java开发框架,结合Mockito和JUnit 5可以让单元测试变得更加高效和灵活。本文将深入介绍使用Mockito和JUnit 5在Spring Boot项目中进行单元测试的23种常见场景,帮助技术人员提升单元测试的能力。
二、环境准备
2.1 添加依赖
在pom.xml文件中添加必要的依赖:
<dependencies>
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Mockito Core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
三、基本测试场景
3.1 简单方法返回值模拟
假设我们有一个UserService类,其中有一个getUserName方法:
public class UserService {
public String getUserName() {
return "default";
}
}
使用Mockito和JUnit 5进行单元测试:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class UserServiceTest {
@Test
public void testSimpleMock() {
UserService userService = mock(UserService.class);
when(userService.getUserName()).thenReturn("testUser");
assertEquals("testUser", userService.getUserName());
}
}
3.2 方法抛出异常模拟
修改UserService类,添加一个可能抛出异常的方法:
public class UserService {
public String getUserName() {
return "default";
}
public void throwException() throws Exception {
throw new Exception("Test exception");
}
}
测试代码:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class UserServiceTest {
@Test
public void testExceptionMock() {
UserService userService = mock(UserService.class);
try {
when(userService.throwException()).thenThrow(new Exception("Mocked exception"));
assertThrows(Exception.class, () -> userService.throwException());
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.3 方法多次调用不同返回值
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class UserServiceTest {
@Test
public void testMultipleReturns() {
UserService userService = mock(UserService.class);
when(userService.getUserName()).thenReturn("first", "second");
assertEquals("first", userService.getUserName());
assertEquals("second", userService.getUserName());
}
}
四、参数匹配场景
4.1 精确参数匹配
假设UserService类有一个根据用户ID获取用户名的方法:
public class UserService {
public String getUserNameById(int id) {
return "default";
}
}
测试代码:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class UserServiceTest {
@Test
public void testExactParameterMatch() {
UserService userService = mock(UserService.class);
when(userService.getUserNameById(1)).thenReturn("user1");
assertEquals("user1", userService.getUserNameById(1));
}
}
4.2 任意参数匹配
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.ArgumentMatchers.anyInt;
public class UserServiceTest {
@Test
public void testAnyParameterMatch() {
UserService userService = mock(UserService.class);
when(userService.getUserNameById(anyInt())).thenReturn("anyUser");
assertEquals("anyUser", userService.getUserNameById(2));
}
}
4.3 自定义参数匹配器
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.mockito.ArgumentMatcher;
public class UserServiceTest {
@Test
public void testCustomParameterMatcher() {
UserService userService = mock(UserService.class);
ArgumentMatcher<Integer> positiveMatcher = i -> i > 0;
when(userService.getUserNameById(org.mockito.ArgumentMatchers.argThat(positiveMatcher))).thenReturn("positiveUser");
assertEquals("positiveUser", userService.getUserNameById(3));
}
}
五、验证方法调用场景
5.1 验证方法是否被调用
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class UserServiceTest {
@Test
public void testMethodInvocation() {
UserService userService = mock(UserService.class);
userService.getUserName();
verify(userService).getUserName();
}
}
5.2 验证方法调用次数
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class UserServiceTest {
@Test
public void testMethodInvocationTimes() {
UserService userService = mock(UserService.class);
userService.getUserName();
userService.getUserName();
verify(userService, times(2)).getUserName();
}
}
5.3 验证方法未被调用
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
public class UserServiceTest {
@Test
public void testMethodNotInvoked() {
UserService userService = mock(UserService.class);
verify(userService, never()).throwException();
}
}
六、模拟对象注入场景
6.1 使用@Mock注解
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
@Mock
private UserService userService;
@Test
public void testMockAnnotation() {
when(userService.getUserName()).thenReturn("mockUser");
assertEquals("mockUser", userService.getUserName());
}
}
6.2 使用@InjectMocks注解
假设我们有一个UserController类依赖于UserService:
public class UserController {
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
public String getUserName() {
return userService.getUserName();
}
}
测试代码:
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(MockitoExtension.class)
public class UserControllerTest {
@Mock
private UserService userService;
@InjectMocks
private UserController userController;
@Test
public void testInjectMocksAnnotation() {
when(userService.getUserName()).thenReturn("mockUser");
assertEquals("mockUser", userController.getUserName());
}
}
七、Spy对象场景
7.1 创建Spy对象
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
public class UserServiceTest {
@Test
public void testSpyObject() {
UserService userService = new UserService();
UserService spyService = spy(userService);
when(spyService.getUserName()).thenReturn("spyUser");
assertEquals("spyUser", spyService.getUserName());
}
}
7.2 Spy对象调用真实方法
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.doCallRealMethod;
public class UserServiceTest {
@Test
public void testSpyCallRealMethod() {
UserService userService = new UserService();
UserService spyService = spy(userService);
doCallRealMethod().when(spyService).getUserName();
assertEquals("default", spyService.getUserName());
}
}
八、异步方法测试场景
8.1 模拟异步方法返回值
假设UserService类有一个异步方法:
import java.util.concurrent.CompletableFuture;
public class UserService {
public CompletableFuture<String> getUserNameAsync() {
return CompletableFuture.completedFuture("default");
}
}
测试代码:
import org.junit.jupiter.api.Test;
import java.util.concurrent.CompletableFuture;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class UserServiceTest {
@Test
public void testAsyncMethod() throws Exception {
UserService userService = mock(UserService.class);
CompletableFuture<String> future = CompletableFuture.completedFuture("asyncUser");
when(userService.getUserNameAsync()).thenReturn(future);
assertEquals("asyncUser", userService.getUserNameAsync().get());
}
}
九、Spring Boot集成测试场景
9.1 测试Spring Bean
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
@SpringBootTest
public class UserServiceSpringTest {
@Autowired
private UserController userController;
@MockBean
private UserService userService;
@Test
public void testSpringBean() {
when(userService.getUserName()).thenReturn("springMockUser");
assertEquals("springMockUser", userController.getUserName());
}
}
9.2 测试RESTful接口
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(UserController.class)
public class UserControllerRestTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
public void testRestfulApi() throws Exception {
when(userService.getUserName()).thenReturn("restMockUser");
mockMvc.perform(get("/user/name"))
.andExpect(status().isOk())
.andExpect(content().string("restMockUser"));
}
}
十、总结
通过以上23种测试场景的介绍,我们可以看到Mockito和JUnit 5在Spring Boot单元测试中的强大功能。合理运用这些技巧,可以提高单元测试的覆盖率和质量,确保代码的稳定性和可维护性。希望本文对技术人员在Spring Boot项目的单元测试方面有所帮助。
更多推荐




所有评论(0)