Spring Boot 单元测试使用教程(仅供参考)_springboot test怎么用
单元测试是软件开发中至关重要的一环,Spring Boot 提供了强大的测试支持。以下是 Spring Boot 单元测试的详细教程。
1. 准备工作
1.1 添加测试依赖
在 pom.xml
中添加测试相关依赖:
org.springframework.boot spring-boot-starter-test test org.springframework spring-test test org.assertj assertj-core 3.24.2 test
1.2 测试类基本结构
import org.junit.jupiter.api.Test;import org.springframework.boot.test.context.SpringBootTest;@SpringBootTestpublic class MyApplicationTests { @Test public void contextLoads() { // 测试Spring上下文是否正常加载 }}
2. 不同类型的测试
2.1 服务层测试
import org.junit.jupiter.api.Test;import org.mockito.InjectMocks;import org.mockito.Mock;import org.mockito.junit.jupiter.MockitoExtension;import org.junit.jupiter.api.extension.ExtendWith;import static org.mockito.Mockito.*;import static org.junit.jupiter.api.Assertions.*;@ExtendWith(MockitoExtension.class)public class UserServiceTest { @Mock private UserRepository userRepository; @InjectMocks private UserService userService; @Test public void testGetUserById() { // 准备测试数据 User mockUser = new User(1L, \"test@example.com\", \"Test User\"); // 定义mock行为 when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser)); // 调用测试方法 User result = userService.getUserById(1L); // 验证结果 assertEquals(\"Test User\", result.getName()); verify(userRepository, times(1)).findById(1L); }}
2.2 控制器层测试
使用MockMvc
import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.web.servlet.MockMvc;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@SpringBootTest@AutoConfigureMockMvcpublic class UserControllerTest { @Autowired private MockMvc mockMvc; @Test public void testGetUser() throws Exception { mockMvc.perform(get(\"/api/users/1\")) .andExpect(status().isOk()) .andExpect(jsonPath(\"$.name\").value(\"Test User\")); }}
使用WebTestClient (WebFlux)
import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.web.reactive.server.WebTestClient;@SpringBootTest@AutoConfigureWebTestClientpublic class UserControllerWebTestClientTest { @Autowired private WebTestClient webTestClient; @Test public void testGetUser() { webTestClient.get().uri(\"/api/users/1\") .exchange() .expectStatus().isOk() .expectBody() .jsonPath(\"$.name\").isEqualTo(\"Test User\"); }}
2.3 数据库测试
使用@DataJpaTest
import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;import static org.assertj.core.api.Assertions.*;@DataJpaTestpublic class UserRepositoryTest { @Autowired private TestEntityManager entityManager; @Autowired private UserRepository userRepository; @Test public void testFindByEmail() { // 准备测试数据 User user = new User(\"test@example.com\", \"Test User\"); entityManager.persist(user); entityManager.flush(); // 调用测试方法 User found = userRepository.findByEmail(user.getEmail()); // 验证结果 assertThat(found.getEmail()).isEqualTo(user.getEmail()); }}
使用@SpringBootTest + 测试数据库
import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.ActiveProfiles;import org.springframework.transaction.annotation.Transactional;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest@ActiveProfiles(\"test\")@Transactionalpublic class UserServiceIntegrationTest { @Autowired private UserService userService; @Autowired private UserRepository userRepository; @Test public void testCreateUser() { User newUser = new User(\"new@example.com\", \"New User\"); User savedUser = userService.createUser(newUser); assertNotNull(savedUser.getId()); assertEquals(\"New User\", savedUser.getName()); User found = userRepository.findById(savedUser.getId()).orElse(null); assertEquals(\"New User\", found.getName()); }}
3. 常用测试技巧
3.1 参数化测试
import org.junit.jupiter.params.ParameterizedTest;import org.junit.jupiter.params.provider.ValueSource;import static org.junit.jupiter.api.Assertions.assertTrue;public class ParameterizedTests { @ParameterizedTest @ValueSource(strings = {\"racecar\", \"radar\", \"madam\"}) public void testPalindromes(String candidate) { assertTrue(StringUtils.isPalindrome(candidate)); }}
3.2 测试异常
import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.assertThrows;public class ExceptionTest { @Test public void testException() { UserService userService = new UserService(); assertThrows(UserNotFoundException.class, () -> { userService.getUserById(999L); }); }}
3.3 测试私有方法
虽然不推荐直接测试私有方法,但有时确实需要:
import org.junit.jupiter.api.Test;import java.lang.reflect.Method;public class PrivateMethodTest { @Test public void testPrivateMethod() throws Exception { MyService service = new MyService(); Method method = MyService.class.getDeclaredMethod(\"privateMethod\", String.class); method.setAccessible(true); String result = (String) method.invoke(service, \"input\"); assertEquals(\"expected\", result); }}
4. 测试配置
4.1 使用测试配置文件
创建 src/test/resources/application-test.properties
:
spring.datasource.url=jdbc:h2:mem:testdbspring.datasource.driver-class-name=org.h2.Driverspring.datasource.username=saspring.datasource.password=spring.h2.console.enabled=true
然后在测试类上使用:
@ActiveProfiles(\"test\")
4.2 使用测试切片
Spring Boot 提供了多种测试切片注解:
-
@WebMvcTest
- 只测试MVC层 -
@DataJpaTest
- 只测试JPA组件 -
@JsonTest
- 只测试JSON序列化 -
@RestClientTest
- 只测试REST客户端@WebMvcTest(UserController.class)public class UserControllerSliceTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test public void testGetUser() throws Exception { when(userService.getUserById(1L)).thenReturn(new User(1L, \"test@example.com\", \"Test User\")); mockMvc.perform(get(\"/api/users/1\")) .andExpect(status().isOk()) .andExpect(jsonPath(\"$.name\").value(\"Test User\")); }}
5. 测试最佳实践
-
命名规范:测试方法名应清晰表达测试意图,如
shouldReturnUserWhenValidIdProvided()
-
单一职责:每个测试方法只测试一个功能点
-
AAA模式:遵循Arrange-Act-Assert模式组织测试代码
-
避免依赖:测试之间不应有依赖关系
-
快速反馈:保持测试快速执行,避免I/O操作
-
覆盖率:追求合理的测试覆盖率,但不要盲目追求100%
-
Mock适度:不要过度使用mock,集成测试也很重要
6. 高级主题
6.1 自定义测试注解
import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.ActiveProfiles;import java.lang.annotation.*;@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@SpringBootTest@ActiveProfiles(\"test\")public @interface MyIntegrationTest {}
然后可以在测试类上使用 @MyIntegrationTest
替代多个注解。
6.2 测试容器支持
使用Testcontainers进行集成测试:
import org.junit.jupiter.api.Test;import org.testcontainers.containers.PostgreSQLContainer;import org.testcontainers.junit.jupiter.Container;import org.testcontainers.junit.jupiter.Testcontainers;import org.springframework.boot.test.context.SpringBootTest;@Testcontainers@SpringBootTestpublic class UserRepositoryTestContainersTest { @Container public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(\"postgres:13\") .withDatabaseName(\"testdb\") .withUsername(\"test\") .withPassword(\"test\"); @Test public void testWithRealDatabase() { // 测试代码 }}
6.3 测试Spring Security
import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.security.test.context.support.WithMockUser;import org.springframework.test.web.servlet.MockMvc;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@SpringBootTest@AutoConfigureMockMvcpublic class SecuredControllerTest { @Autowired private MockMvc mockMvc; @Test @WithMockUser(username=\"admin\", roles={\"ADMIN\"}) public void testAdminEndpoint() throws Exception { mockMvc.perform(get(\"/api/admin\")) .andExpect(status().isOk()); } @Test @WithMockUser(username=\"user\", roles={\"USER\"}) public void testAdminEndpointForbidden() throws Exception { mockMvc.perform(get(\"/api/admin\")) .andExpect(status().isForbidden()); }}
7. 总结
Spring Boot 提供了全面的测试支持,从单元测试到集成测试,从Mock测试到真实环境测试。合理使用这些工具可以大大提高代码质量和开发效率。
记住测试金字塔原则:多写单元测试,适量集成测试,少量端到端测试。