本文目录导读:

我来详细介绍SpringBoot集成测试的模拟环境搭建和常用方案。
测试环境搭建依赖
Maven依赖配置
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Mockito -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<!-- 如果需要Web环境 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>test</scope>
</dependency>
<!-- 数据库测试内存库 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<!-- Testcontainers (容器化测试) -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.19.0</version>
<scope>test</scope>
</dependency>
测试模拟方案
Mockito模拟
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void testFindUserById() {
// 模拟数据
User mockUser = new User(1L, "张三", "zhangsan@test.com");
Mockito.when(userRepository.findById(1L))
.thenReturn(Optional.of(mockUser));
// 执行测试
User result = userService.findUserById(1L);
// 验证结果
assertEquals("张三", result.getName());
Mockito.verify(userRepository).findById(1L);
}
}
Spring Boot集成测试
@SpringBootTest
@AutoConfigureMockMvc
@Transactional // 测试后自动回滚
public class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@Test
void testCreateUser() throws Exception {
// 准备测试数据
User user = new User();
user.setName("测试用户");
user.setEmail("test@example.com");
// 执行请求
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(user)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.name").value("测试用户"));
}
private String asJsonString(Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
切片测试
// Web层测试
@WebMvcTest(UserController.class)
public class UserControllerSliceTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void testGetUser() throws Exception {
// 模拟Service层
Mockito.when(userService.findUserById(1L))
.thenReturn(new User(1L, "张三", "test@test.com"));
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("张三"));
}
}
// 数据层测试
@DataJpaTest
public class UserRepositoryTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository userRepository;
@Test
void testFindByEmail() {
// 准备数据
User user = new User("张三", "test@test.com");
entityManager.persist(user);
entityManager.flush();
// 执行查询
Optional<User> found = userRepository.findByEmail("test@test.com");
// 验证结果
assertTrue(found.isPresent());
assertEquals("张三", found.get().getName());
}
}
数据库模拟
H2内存数据库
# application-test.yml
spring:
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: create-drop
database-platform: org.hibernate.dialect.H2Dialect
h2:
console:
enabled: true
Testcontainers容器化测试
@SpringBootTest
@Testcontainers
public class DatabaseContainerTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:14")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Autowired
private UserRepository userRepository;
@Test
void testDatabaseInteraction() {
// 测试实际的数据库操作
User user = new User("张三", "test@test.com");
userRepository.save(user);
assertNotNull(user.getId());
}
}
外部服务模拟
Redis模拟
@SpringBootTest
@Testcontainers
public class RedisTest {
@Container
static GenericContainer<?> redis = new GenericContainer<>("redis:6-alpine")
.withExposedPorts(6379);
@DynamicPropertySource
static void configureRedis(DynamicPropertyRegistry registry) {
registry.add("spring.redis.host", redis::getHost);
registry.add("spring.redis.port", redis::getFirstMappedPort);
}
@Autowired
private StringRedisTemplate redisTemplate;
@Test
void testRedisOperations() {
redisTemplate.opsForValue().set("key", "value");
assertEquals("value", redisTemplate.opsForValue().get("key"));
}
}
外部API Mock
@SpringBootTest
@AutoConfigureMockMvc
public class ExternalApiTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private ExternalApiService externalApiService;
@Test
void testExternalCall() throws Exception {
// 模拟外部API响应
Mockito.when(externalApiService.callExternalApi())
.thenReturn(new ExternalResponse("success", 200));
mockMvc.perform(post("/api/process")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"data\":\"test\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value("success"));
}
}
WireMock模拟HTTP服务
@SpringBootTest
@WireMockTest(httpPort = 8089)
public class WireMockTest {
@Test
void testExternalHttpCall() {
// 配置WireMock响应
stubFor(get(urlEqualTo("/api/data"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/json")
.withBody("{\"id\":1, \"name\":\"test\"}")));
// 测试代码
ResponseEntity<String> response = restTemplate.getForEntity(
"http://localhost:8089/api/data", String.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
}
}
Spring Cloud组件模拟
配置中心模拟
@SpringBootTest
@EnableConfigurationProperties
@ContextConfiguration(initializers = ConfigDataInitializer.class)
public class ConfigTest {
@Value("${test.property}")
private String testProperty;
@Test
void testConfigProperty() {
assertEquals("test-value", testProperty);
}
}
服务发现模拟
@SpringBootTest
@AutoConfigureMockMvc
public class ServiceDiscoveryTest {
@MockBean
private DiscoveryClient discoveryClient;
@Test
void testServiceDiscovery() {
// 模拟服务发现
List<ServiceInstance> instances = Arrays.asList(
new DefaultServiceInstance("service1", "user-service", "localhost", 8080, false)
);
Mockito.when(discoveryClient.getInstances("user-service"))
.thenReturn(instances);
// 执行测试
List<ServiceInstance> result = discoveryClient.getInstances("user-service");
assertEquals(1, result.size());
}
}
测试最佳实践
测试配置隔离
@TestConfiguration
public class TestConfig {
@Bean
@Primary
public DataSource testDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
@Bean
@Primary
public RestTemplate testRestTemplate() {
return new RestTemplate();
}
}
测试分类和过滤
// 定义测试分类
@Tag("integration")
@Tag("database")
public class DatabaseIntegrationTest {
// 测试代码
}
// 运行特定标签的测试
// mvn test -Dgroups="integration"
测试前后置处理
@SpringBootTest
public class TestLifecycleTest {
@BeforeAll
static void initAll() {
// 全局初始化
}
@BeforeEach
void init() {
// 每个测试方法前执行
}
@Test
void testSomething() {
// 测试逻辑
}
@AfterEach
void tearDown() {
// 每个测试方法后执行
}
@AfterAll
static void tearDownAll() {
// 全局清理
}
}
性能考虑
- 测试范围选择:控制测试范围,避免不必要的上下文加载
- 并行测试:合理配置并行执行策略
- 资源清理:确保测试后资源被正确释放
- 依赖管理:管理好测试环境的依赖版本
这个测试模拟方案可以帮助你在开发过程中快速验证业务逻辑,同时减少对外部环境的依赖,根据项目实际需求,选择合适的测试方案组合。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播