Spring Boot starter测试

发布时间:2026/5/18 16:25:17

Spring Boot starter测试 Spring Boot starter测试引言测试是保证软件质量的关键环节对于Spring Boot应用来说需要针对不同层次和目标进行测试。单元测试验证单个组件的行为集成测试验证组件间的协作Slice测试则针对特定功能进行隔离测试。本文将详细介绍Spring Boot应用的各种测试策略、工具使用和最佳实践。一、测试依赖1.1 Maven依赖dependencies !-- Spring Boot Test -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency !-- JUnit 5 -- dependency groupIdorg.junit.jupiter/groupId artifactIdjunit-jupiter/artifactId scopetest/scope /dependency !-- Mockito -- dependency groupIdorg.mockito/groupId artifactIdmockito-core/artifactId scopetest/scope /dependency !-- AssertJ -- dependency groupIdorg.assertj/groupId artifactIdassertj-core/artifactId scopetest/scope /dependency !-- Spring Security Test -- dependency groupIdorg.springframework.security/groupId artifactIdspring-security-test/artifactId scopetest/scope /dependency !-- Database Test -- dependency groupIdcom.h2database/groupId artifactIdh2/artifactId scopetest/scope /dependency /dependencies二、单元测试2.1 Service单元测试ExtendWith(MockitoExtension.class) class UserServiceTest { Mock private UserRepository userRepository; Mock private PasswordEncoder passwordEncoder; InjectMocks private UserService userService; Test void shouldCreateUserSuccessfully() { // Given String rawPassword password123; String encodedPassword encoded_password; when(passwordEncoder.encode(rawPassword)) .thenReturn(encodedPassword); when(userRepository.save(any(User.class))) .thenAnswer(invocation - { User user invocation.getArgument(0); user.setId(1L); return user; }); // When CreateUserRequest request new CreateUserRequest(); request.setUsername(testuser); request.setPassword(rawPassword); User result userService.createUser(request); // Then assertThat(result.getId()).isEqualTo(1L); assertThat(result.getPassword()).isEqualTo(encodedPassword); verify(userRepository).save(any(User.class)); } Test void shouldThrowExceptionWhenUsernameExists() { // Given when(userRepository.existsByUsername(existing)) .thenReturn(true); // When Then assertThatThrownBy(() - { CreateUserRequest request new CreateUserRequest(); request.setUsername(existing); userService.createUser(request); }) .isInstanceOf(UsernameExistsException.class) .hasMessageContaining(existing); } }2.2 异步测试ExtendWith(MockitoExtension.class) class AsyncServiceTest { Mock private ExternalApiClient externalApiClient; InjectMocks private AsyncService asyncService; Test void shouldReturnAsyncResult() throws Exception { // Given String expectedResult async_result; CompletableFutureString future CompletableFuture.completedFuture(expectedResult); when(externalApiClient.fetchData()) .thenReturn(future); // When FutureString result asyncService.fetchDataAsync(); // Then assertThat(result.get(5, TimeUnit.SECONDS)) .isEqualTo(expectedResult); } }三、集成测试3.1 Spring Boot集成测试SpringBootTest AutoConfigureMockMvc ActiveProfiles(test) class UserControllerIntegrationTest { Autowired private MockMvc mockMvc; Autowired private ObjectMapper objectMapper; Autowired private UserRepository userRepository; AfterEach void cleanup() { userRepository.deleteAll(); } Test void shouldCreateUser() throws Exception { // Given CreateUserRequest request new CreateUserRequest(); request.setUsername(testuser); request.setPassword(password123); // When Then mockMvc.perform(post(/api/users) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isCreated()) .andExpect(jsonPath($.username) .value(testuser)) .andExpect(jsonPath($.id).exists()); } Test void shouldReturn400WhenInvalidRequest() throws Exception { // Given CreateUserRequest request new CreateUserRequest(); // 缺少必需字段 // When Then mockMvc.perform(post(/api/users) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isBadRequest()); } }3.2 数据库集成测试# test/resources/application-test.yml spring: datasource: url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY-1 driver-class-name: org.h2.Driver username: sa password: jpa: hibernate: ddl-auto: create-drop show-sql: true properties: hibernate: format_sql: true h2: console: enabled: true四、Slice测试4.1 Web Slice测试WebMvcTest(UserController.class) Import(TestSecurityConfig.class) class UserControllerTest { Autowired private MockMvc mockMvc; MockBean private UserService userService; Autowired private ObjectMapper objectMapper; Test WithMockUser(roles USER) void shouldGetUser() throws Exception { // Given User user new User(); user.setId(1L); user.setUsername(testuser); when(userService.findById(1L)).thenReturn(user); // When Then mockMvc.perform(get(/api/users/1)) .andExpect(status().isOk()) .andExpect(jsonPath($.username).value(testuser)); } }4.2 Data JPA Slice测试DataJpaTest AutoConfigureTestDatabase(replace AutoConfigureTestDatabase.Replace.NONE) Import(TestDataSourceConfig.class) class UserRepositoryTest { Autowired private UserRepository userRepository; Test void shouldFindByUsername() { // Given User user new User(); user.setUsername(testuser); user.setPassword(password); userRepository.save(user); // When OptionalUser found userRepository.findByUsername(testuser); // Then assertThat(found).isPresent(); assertThat(found.get().getUsername()).isEqualTo(testuser); } }4.3 Service Slice测试JdbcTest DataJdbcTest Import(DatasourceConfig.class) class UserServiceJdbcTest { Autowired private JdbcTemplate jdbcTemplate; private UserService userService; BeforeEach void setup() { userService new UserService( new JdbcUserRepository(jdbcTemplate)); } Test void shouldCreateUser() { // Given User user new User(); user.setUsername(testuser); // When User created userService.createUser(user); // Then assertThat(created.getId()).isNotNull(); assertThat(created.getUsername()).isEqualTo(testuser); } }五、MockMvc详解5.1 请求匹配Test void shouldMatchRequests() throws Exception { mockMvc.perform( // 基本请求 get(/api/users/1) .accept(MediaType.APPLICATION_JSON) .header(X-Custom-Header, value) .param(sort, name) .cookie(new Cookie(session, 123)) // JSON Body post(/api/users) .contentType(MediaType.APPLICATION_JSON) .content({\username\:\test\}) // 文件上传 multipart(/api/upload) .file(file, content.getBytes()) // 带查询参数 get(/api/users) .queryParam(page, 0) .queryParam(size, 10) ) .andExpect(status().isOk()); }5.2 结果验证Test void shouldVerifyResults() throws Exception { mockMvc.perform(get(/api/users/1)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath($.id).value(1)) .andExpect(jsonPath($.username).value(testuser)) .andExpect(header().string(X-Custom-Header, value)) .andExpect(cookie().httpOnly(session, true)) .andExpect(model().attribute(user, notNullValue())) .andExpect(view().name(userView)) .andExpect(forwardedUrl(/WEB-INF/views/userView.jsp)); }六、测试配置6.1 测试配置类TestConfiguration public class TestConfig { Bean Primary public ExternalApiClient testApiClient() { ExternalApiClient mockClient mock(ExternalApiClient.class); when(mockClient.fetchData()).thenReturn(mock_data); return mockClient; } Bean public TestPropertyValues testProperties() { return TestPropertyValues.of( app.external-api.urlhttp://localhost:8089, app.cache.enabledfalse ); } }6.2 测试切片注解// Web层测试 WebMvcTest(controllers UserController.class) // 数据层测试 DataJpaTest DataJdbcTest JdbcTest // 服务层测试 ServiceTest // 消息层测试 JsonTest // REST客户端测试 RestClientTest(UserClient.class) // 自动配置测试 AutoConfigureMockMvc AutoConfigureTestDatabase AutoConfigureCache七、测试数据准备7.1 Sql注解Test Sql({ /sql/cleanup.sql, /sql/test-data.sql }) Sql(scripts /sql/cleanup.sql, executionPhase Sql.ExecutionPhase.AFTER_TEST_METHOD) void shouldOperateWithTestData() { // 使用TestData中的数据 }7.2 TestContainersTestcontainers SpringBootTest class DatabaseIntegrationTest { Container static MySQLContainer? mysql new MySQLContainer( DockerImageName.parse(mysql:8.0) ).withDatabaseName(test) .withUsername(test) .withPassword(test); DynamicPropertySource static void properties(DynamicPropertyRegistry registry) { registry.add(spring.datasource.url, mysql::getJdbcUrl); registry.add(spring.datasource.username, mysql::getUsername); registry.add(spring.datasource.password, mysql::getPassword); } }八、性能测试8.1 JMH集成State(Scope.Thread) BenchmarkMode(Mode.AverageTime) OutputTimeUnit(TimeUnit.MILLISECONDS) public class UserServiceBenchmark { private UserService userService; Setup public void setup() { userService new UserService(mockRepository); } Benchmark public void createUser() { userService.createUser(new CreateUserRequest()); } }九、测试覆盖率9.1 JaCoCo配置plugin groupIdorg.jacoco/groupId artifactIdjacoco-maven-plugin/artifactId configuration excludes exclude**/*Impl.class/exclude exclude**/dto/*.class/exclude /excludes /configuration /plugin9.2 覆盖率报告mvn clean verify jacoco:report # 查看 target/site/jacoco/index.html总结Spring Boot提供了完整的测试支持体系从单元测试到集成测试从Slice测试到性能测试都有相应的工具和最佳实践。合理编写测试可以有效保证代码质量发现潜在问题提高系统的可维护性。测试金字塔原则建议大量单元测试作为基础适量的集成测试验证组件协作少量的端到端测试验证完整功能。

相关新闻