@SpringBootTest 详解及详细代码示例

@SpringBootTest 详解及详细代码示例

@SpringBootTest 是 Spring Boot 提供的核心测试注解,用于启动 完整的 Spring 应用上下文,支持集成测试(Integration Test)。它通过加载 ApplicationContext,验证组件间的协作,适用于需要完整依赖链的测试场景。


一、核心功能

  1. 启动完整应用上下文

    • 加载 @SpringBootApplication 主配置类。
    • 支持 @Autowired 注入 Bean。
  2. 配置环境隔离

    • 通过 properties 属性覆盖配置。
    • 支持随机端口(webEnvironment = WebEnvironment.RANDOM_PORT)。
  3. 切片测试支持

    • 结合 @AutoConfigureMockMvc@AutoConfigureDataJpa 等实现分层测试。
  4. 测试切片(Test Slices)

    • 仅加载部分配置(如 @WebMvcTest@DataJpaTest),提升测试速度。

二、与 @Test 注解的区别

特性@SpringBootTest@Test(JUnit 注解)
上下文加载启动完整 Spring 容器
依赖注入支持 @Autowired
执行速度较慢(完整上下文)快(无容器)
适用场景集成测试(需完整依赖链)单元测试(无依赖或模拟依赖)

三、详细代码示例

3.1 基础集成测试
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class UserServiceIntegrationTest {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserService userService;

    @Test
    void testUserCreation() {
        // 1. 准备测试数据
        User newUser = new User(0, "Alice");

        // 2. 执行测试方法
        User savedUser = userService.createUser(newUser);

        // 3. 验证结果
        assertNotNull(savedUser.getId());
        assertEquals("Alice", savedUser.getName());

        // 4. 验证数据库操作
        User dbUser = userRepository.findById(savedUser.getId()).orElseThrow();
        assertEquals("Alice", dbUser.getName());
    }
}

// 被测服务
@Service
class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User createUser(User user) {
        return userRepository.save(user);
    }
}

// 数据库接口
interface UserRepository extends JpaRepository<User, Integer> {}

// 实体类
@Entity
record User(@Id @GeneratedValue(strategy = GenerationType.IDENTITY) int id, String name) {}
3.2 配置环境隔离
@SpringBootTest(properties = {
    "app.env=test",
    "spring.datasource.url=jdbc:h2:mem:testdb"
})
class ConfigOverrideTest {

    @Autowired
    private AppConfig appConfig;

    @Test
    void testConfigOverride() {
        assertEquals("test", appConfig.getEnv());
    }
}

@Configuration
@ConfigurationProperties(prefix = "app")
class AppConfig {
    private String env;
    // Getter/Setter
}
3.3 随机端口测试
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class WebIntegrationTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void testApiEndpoint() {
        // 1. 发送 GET 请求
        ResponseEntity<String> response = restTemplate.getForEntity("/api/users", String.class);

        // 2. 验证状态码和响应体
        assertEquals(200, response.getStatusCodeValue());
        assertTrue(response.getBody().contains("Alice"));
    }
}
3.4 切片测试(Web 层)
@WebMvcTest(UserController.class)
@AutoConfigureMockMvc
class WebSliceTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    void testGetUser() throws Exception {
        // 1. 模拟依赖行为
        User mockUser = new User(1, "Alice");
        when(userService.getUserById(1)).thenReturn(mockUser);

        // 2. 发送请求并验证响应
        mockMvc.perform(get("/api/users/1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.name").value("Alice"));
    }
}

@RestController
@RequestMapping("/api/users")
class UserController {
    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public User getUser(@PathVariable int id) {
        return userService.getUserById(id);
    }
}
3.5 事务回滚测试
@SpringBootTest
@Transactional
@Rollback
class TransactionalTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void testTransactionRollback() {
        // 1. 创建用户
        User user = new User(0, "Bob");
        userRepository.save(user);

        // 2. 验证数据库状态(事务未提交)
        assertFalse(userRepository.findById(user.getId()).isPresent());
    }
}

四、高级配置

4.1 指定启动类
@SpringBootTest(classes = MyCustomApplication.class)
class CustomContextTest {}
4.2 排除自动配置
@SpringBootTest(excludeAutoConfiguration = SecurityAutoConfiguration.class)
class NoSecurityTest {}
4.3 动态属性覆盖
@TestPropertySource(properties = "app.feature.toggle=true")
@SpringBootTest
class FeatureToggleTest {}

五、最佳实践

  1. 分层测试策略

    • 单元测试(@Test + Mockito)→ 切片测试(@WebMvcTest)→ 集成测试(@SpringBootTest)。
  2. 避免全量测试

    • 仅在需要完整上下文时使用 @SpringBootTest,优先使用切片测试提升速度。
  3. 测试数据管理

    • 使用 @Sql 注解初始化测试数据:
      @Sql("/test-data.sql")
      @SpringBootTest
      class DataDrivenTest {}
      
  4. 并行测试

    • 配置 spring.main.web-application-type=none 禁用 Web 环境加速测试。

通过 @SpringBootTest,开发者可以编写覆盖完整业务流的集成测试,确保系统各组件协同工作。结合切片测试和 Mockito,可实现高效的测试金字塔策略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值