Spring 测试:TestContext 与事务回滚

引言

单元测试要 Mock,集成测试要真容器。Spring 的 TestContext 框架让你在 JUnit 里启动一个真实 ApplicationContext,把 Bean 注入测试类;更妙的是测试方法标 @Transactional默认回滚,写库测试互不污染。本章掌握集成测试的最小骨架与回滚语义。

核心概念

  • 模块:spring-test;JUnit 5 用 @ExtendWith(SpringExtension.class) 接入,或直接用组合注解 @SpringJUnitConfig(= ExtendWith + @ContextConfiguration)。
  • @ContextConfiguration:指定配置来源——classes = AppConfig.class(JavaConfig)或 locations = "classpath:beans.xml"(XML)。
  • 上下文缓存:相同配置的测试类共享同一个 ApplicationContext(框架级缓存,大大提速);配置不同才重建。
  • 测试类里可 @Autowired 注入被测 Bean、@Value 取属性,配合 @ActiveProfiles("test")@TestPropertySource 切环境。
  • 事务回滚@Transactional 标在测试方法/类上时,TransactionalTestExecutionListener 会在方法前开事务、方法后回滚——测试写的库数据不残留;类级别的 @Transactional 对类内每个方法都生效。
  • 想真提交:@Rollback(false)@Commit 标注;也可在测试里注入 TransactionTemplate 自主控制。
  • 上下文被污染时用 @DirtiesContext 标记“本测试后重建上下文”(有成本,慎用)。

代码示例

@SpringJUnitConfig(classes = TestConfig.class)   // 启动真实容器
@ActiveProfiles("test")                          // 测试 profile
@Transactional                                   // 类级:每个测试方法事务+回滚
class AccountServiceTest {
    @Autowired AccountService accountService;
    @Autowired JdbcTemplate jdbcTemplate;

    @Test
    void transfer_should_rollback() {
        accountService.transfer(1L, 2L, 50);
        // 测试结束自动回滚:balance 断言只在此事务内成立,
        // 方法返回后数据恢复原状,其他测试不受影响
        Long balance = jdbcTemplate.queryForObject(
                "SELECT balance FROM account WHERE id = 1", Long.class);
        assertEquals(950L, balance);
    }

    @Test
    @Rollback(false) // 个别用例想保留数据,显式声明
    void keep_data() { /* 提交 */ }
}

// TestConfig 示意:嵌入式库数据源 + 事务管理器 + JdbcTemplate
// @Bean DataSource ds = 内嵌数据库(如 H2,需驱动依赖);
// @Bean PlatformTransactionManager = new DataSourceTransactionManager(ds);

注意点

  • 回滚前提:容器里存在 PlatformTransactionManager Bean(默认按名 transactionManager 查找,以官方文档为准),否则 @Transactional 测试直接报错。
  • 被测服务若吞了异常或没走代理,测试里照样验不出回滚(回滚语义在“测试方法的事务”上,不等于业务代码自动正确)。
  • 上下文缓存按配置指纹匹配,随意加 @DirtiesContext 会让整套测试变慢。
  • @BeforeEach/@AfterEach 在测试事务之内执行;想在事务外准备数据请用别的手段(以官方文档为准)。
  • 集成测试别连生产库——测试数据管理(构造/清理)与真实事务语义要保持可控,常用独立测试库或嵌入式库。

小结

Spring 测试三板斧:@SpringJUnitConfig 起容器、@Autowired 注入被测对象、@Transactional 让测试事务自动回滚。真容器 + 回滚隔离,让“带数据库的集成测试”既能跑又互不污染。此章是前半段 Spring Core 的收尾,后半段 Web MVC 的测试仍复用同一套 TestContext。

笔记加载中…