当前位置: 首页 > news >正文

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测试到性能测试都有相应的工具和最佳实践。合理编写测试可以有效保证代码质量发现潜在问题提高系统的可维护性。测试金字塔原则建议大量单元测试作为基础适量的集成测试验证组件协作少量的端到端测试验证完整功能。
http://www.rkmt.cn/news/1310144.html

相关文章:

  • 从芯片手册到实际电路:深入解读74LS74的SD/RD异步复位和D触发器空翻问题(避坑指南)
  • Equalizer APO:解锁Windows系统级音频均衡的完整指南
  • 5个rc-form高级技巧:动态字段、异步验证、嵌套表单实战
  • YOLO26可运行项目,有上百个模块,都是我自己之前发SCI二区时,集成的一些模块,适合需要算法创新,模块改进的朋友。目标检测,语义分割,关键点识别通用项目
  • 收藏夹500篇文章看了不到10篇,我用Claude Code帮我全整理了
  • 告别昂贵授权!用J-Link+TopJTAG Probe免费玩转FPGA/STM32边界扫描测试
  • PyFluent:工业级CFD仿真的Python自动化解决方案
  • 佛山二手名表回收避坑攻略,内行教你避开黑心套路 - 奢侈品回收测评
  • VR-Reversal:沉浸式视频降维转换与视角记录渲染工具
  • 临床医生转型科研者的最后一块拼图:NotebookLM医学研究辅助(含NIH R01标书智能润色模块+统计假设自动校验功能)
  • DLSS Swapper:一键切换游戏DLSS版本,让NVIDIA显卡性能起飞
  • ADS-B Receiver Pro - Flight Web 使用说明书
  • 如何用3步快速掌握XTDrone无人机仿真平台?
  • 2025届学术党必备的五大降重复率神器推荐
  • 如何用Illustrator脚本在3分钟内完成1小时的设计工作
  • 基于开源项目构建实时语音AI对话系统:从ASR、LLM到TTS的完整技术栈解析
  • 如何用智能标记插件3秒筛选最新招聘岗位:开源求职助手完整指南
  • Chat-with-NeRF:三维场景重建与对话式AI的融合实践
  • 5分钟搞定!Postman便携版:你的API测试随身工具箱 [特殊字符]
  • 昆山打官司胜诉率高的律师服务选择要点分析 - 品牌排行榜
  • 【Unity】从零到一:Render Streaming云渲染环境搭建与实战避坑指南
  • 基于Python构建Telegram-AI桥接机器人:从架构设计到生产部署
  • Stenographer核心架构深度解析:从数据包嗅探到磁盘写入的完整流程指南 [特殊字符]
  • Awesome-AI项目解析:如何高效利用AI资源导航与构建个人知识体系
  • 为Grok等大模型构建高效网页内容抓取与结构化提取工具
  • 浏览器音乐解锁终极指南:3分钟轻松解密各大平台加密音频
  • Windows开发者如何快速构建专业级词法语法分析器?WinFlexBison终极解决方案
  • 15分钟搞定黑苹果EFI配置?OpCore Simplify让复杂设置小白化
  • 创业团队如何利用Taotoken统一管理多个AI模型的API调用成本
  • 2026 年天津离婚律所口碑榜,坚守抚养权底线 - 速递信息