如何在@RunWith(Junit4.class)的DBUnit测试中实现事务回滚?
在JUnit4中实现DBUnit测试的事务回滚
不用SpringJUnitClassRunner也完全能搞定DBUnit测试后的事务回滚,核心思路就是手动接管事务控制权,不让DBUnit或JDBC自动提交数据,测试完成后统一回滚。下面是具体的实现步骤和代码示例:
方法一:手动管理JDBC+DBUnit连接事务
这种方式最直接,完全自己控制事务的开启和回滚:
1. 定义成员变量
先声明需要用到的DBUnit连接和JDBC连接对象:
import org.dbunit.database.DatabaseConnection; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.xml.FlatXmlDataSetBuilder; import org.dbunit.operation.DatabaseOperation; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.sql.Connection; import java.sql.DriverManager; import java.io.File; public class MyDbUnitTest { private DatabaseConnection dbUnitConnection; private Connection jdbcConnection;
2. 测试前初始化:开启事务、加载测试数据
在@Before方法里,获取JDBC连接并关闭自动提交(这是关键!),然后初始化DBUnit连接并插入测试数据:
@Before public void setUp() throws Exception { // 1. 获取JDBC连接(这里用DriverManager示例,也可以用数据源) jdbcConnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test_db", "user", "pass"); // 关闭自动提交,开启事务 jdbcConnection.setAutoCommit(false); // 2. 初始化DBUnit连接 dbUnitConnection = new DatabaseConnection(jdbcConnection); // 3. 加载测试数据集并插入到数据库 IDataSet dataSet = new FlatXmlDataSetBuilder().build(new File("src/test/resources/test-data.xml")); DatabaseOperation.CLEAN_INSERT.execute(dbUnitConnection, dataSet); }
3. 测试方法(正常编写业务逻辑)
@Test public void testSomeDatabaseOperation() throws Exception { // 这里编写你的测试逻辑:比如调用DAO方法修改数据 // ... // 用DBUnit断言数据是否符合预期 // IDataSet actualDataSet = dbUnitConnection.createDataSet(); // Assertion.assertEquals(dataSet, actualDataSet); }
4. 测试后回滚事务、清理资源
在@After方法里,不管测试成功还是失败,都执行回滚,然后关闭连接:
@After public void tearDown() throws Exception { if (jdbcConnection != null) { // 回滚所有未提交的操作 jdbcConnection.rollback(); jdbcConnection.close(); } if (dbUnitConnection != null) { dbUnitConnection.close(); } } }
方法二:用DBUnit的IDatabaseTester简化操作
如果你习惯用DBUnit的IDatabaseTester接口(比如DataSourceDatabaseTester),也可以通过它来控制事务:
import org.dbunit.DataSourceDatabaseTester; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.xml.FlatXmlDataSetBuilder; import org.dbunit.operation.DatabaseOperation; import org.junit.After; import org.junit.Before; import org.junit.Test; import javax.sql.DataSource; import java.sql.Connection; import java.io.File; public class MyDbUnitTest { private DataSourceDatabaseTester databaseTester; @Before public void setUp() throws Exception { // 替换成你的数据源获取逻辑 DataSource dataSource = getYourDataSource(); databaseTester = new DataSourceDatabaseTester(dataSource); // 获取JDBC连接并关闭自动提交 Connection conn = databaseTester.getConnection().getConnection(); conn.setAutoCommit(false); // 设置测试数据和初始化操作 IDataSet dataSet = new FlatXmlDataSetBuilder().build(new File("src/test/resources/test-data.xml")); databaseTester.setDataSet(dataSet); databaseTester.setSetUpOperation(DatabaseOperation.CLEAN_INSERT); databaseTester.onSetup(); } @Test public void testDatabaseLogic() throws Exception { // 你的测试代码 } @After public void tearDown() throws Exception { // 回滚事务 databaseTester.getConnection().getConnection().rollback(); // 清理资源 databaseTester.onTearDown(); } private DataSource getYourDataSource() { // 实现你的数据源创建逻辑,比如用BasicDataSource // ... } }
关键注意点
- 一定要关闭JDBC连接的
autoCommit:默认情况下JDBC连接是自动提交的,所以必须手动设置为false,否则测试中的操作会直接写入数据库,回滚就无效了。 - 回滚要放在
@After方法里:不管测试是否抛出异常,都要执行回滚,保证数据库不会残留测试数据。 - 如果用数据源,确保连接是可重复利用且能正确关闭的:避免连接泄漏问题。
内容的提问来源于stack exchange,提问作者mvoase
相关产品推荐
相关产品推荐

