咨询otj-pg-embedded单元测试后的数据回滚机制
咨询otj-pg-embedded单元测试后的数据回滚机制
嗨,针对你提到的otj-pg-embedded单元测试数据回滚的问题,我来分享几个实用的方案和思路,刚好之前做类似的测试优化时踩过这些坑~
首先直接回应你的核心疑问:otj-pg-embedded本身并没有提供类似Git标签那种一键式的回滚API,但它基于原生PostgreSQL,我们可以利用PostgreSQL的特性+组件的测试隔离能力,实现几乎一样的效果,完全不用手动追踪所有创建的数据。
下面是几种可落地的方案,你可以根据自己的测试场景选择:
方案一:用PostgreSQL保存点实现轻量“标签式”回滚
这个方案最接近你想要的Git标签效果,轻量且高效:
- 在每个测试方法开始前,执行SQL创建一个保存点:
SAVEPOINT test_initial_state; - 不管测试成功还是失败,在测试结束后执行回滚命令:
ROLLBACK TO SAVEPOINT test_initial_state; - 注意:如果你的测试代码里有显式的事务提交操作(比如手动调用
COMMIT,或者某些框架/方法内部触发了提交),这个方案会失效——因为PostgreSQL的保存点是依附于当前事务的,一旦事务提交,所有保存点都会被销毁。
方案二:为每个测试克隆独立的模板数据库
如果你的测试里有事务提交操作,或者需要绝对干净的测试环境,这个方案最可靠:
- 先在测试类的全局初始化阶段(比如JUnit的
@BeforeAll),创建一个模板数据库:- 启动EmbeddedPostgres后,创建一个空数据库并标记为模板库:
CREATE DATABASE test_template WITH IS_TEMPLATE = true; - 在这个模板库上执行你的Liquibase脚本,初始化表结构和基础数据。
- 启动EmbeddedPostgres后,创建一个空数据库并标记为模板库:
- 每个测试方法开始前(
@BeforeEach),快速克隆这个模板库作为当前测试的专用数据库:CREATE DATABASE test_current TEMPLATE test_template; - 测试结束后(
@AfterEach),删除这个临时数据库:DROP DATABASE test_current; - 这个方案的隔离性拉满,完全不会有数据串扰的问题,唯一的小缺点是如果模板库初始化比较重,单个测试的启动时间会稍有增加,但对于大多数单元测试来说完全在可接受范围内。
方案三:封装批量清理脚本(兜底方案)
如果你暂时不想改测试结构,也可以把手动清理的逻辑封装成公共方法,避免逐个追踪数据的麻烦:
- 写一个通用方法,执行SQL清空所有业务表:
(TRUNCATE TABLE table1, table2, table3 CASCADE;CASCADE会自动处理外键关联的数据,不用你手动处理依赖) - 或者利用Liquibase的能力,直接重置数据库的初始状态:比如重新执行初始化脚本的基础部分,或者调用
clearCheckSums后重新同步。
另外补充个小技巧:如果用JUnit 5,可以把这些回滚/克隆逻辑封装成一个自定义Extension,这样所有测试类都能直接复用,不用每个类都写重复的@BeforeEach/@AfterEach代码。
备注:内容来源于stack exchange,提问作者Mike Sonarov
相关产品推荐
相关产品推荐

