如何在@AfterClass中回滚数据库更改?

时间:2012-07-08 22:39:11

标签: java junit rollback

我知道如何配置Spring / JUnit以在每个测试用例后回滚。 我所追求的是一种为所有测试用例启动和回滚一个事务的方法。

我正在使用@BeforeClass为几个测试用例准备我的HSQL数据库。然后我想在@AfterClass中的所有测试用例结束后回滚更改。

实现此回滚的最佳方法是什么?

这是我的代码示例:

@BeforeClass
public static void setupDB(){
ApplicationContext context = new ClassPathXmlApplicationContext(
        "classpath:/spring/applicationContext-services-test.xml");
//- get beans and insert some records to the DB
...
}

@AfterClass
public static void cleanUp(){
   ??? what should go here?
}

有关在AfterClass中进行回滚的最佳方法的任何想法吗?

感谢所有..

5 个答案:

答案 0 :(得分:5)

如果您在每次测试后回滚并使用Spring是可以接受的,那么我项目中的以下代码段可能会对您有所帮助:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/net/sukharevd/shopzilla/model/application-context-dao.xml" })
@TestExecutionListeners(DependencyInjectionTestExecutionListener.class)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public class HibernateCategoryDaoTest extends AbstractTransactionalJUnit4SpringContextTests {

答案 1 :(得分:3)

您可能不希望在课后进行回滚,但是在每次测试之后。测试不保证每次都以相同的顺序运行,因此您可能会得到不同的结果。单元测试应该是隔离的。

您可以使用spring test runner来注释您的类和回滚事务

@RunWith(SpringJUnit4ClassRunner.class)
@TransactionConfiguration(defaultRollback=true)
public static class YourTestClass {

    @Test
    @Transactional
    public void aTest() {
        // do some db stuff that will get rolled back at the end of the test
    }

}

一般情况下,您还应该尽量避免在单元测试中遇到真正的数据库。击中数据库的测试通常是集成级别测试(或甚至更粗糙的测试,如验收测试)。 DBUnit http://www.dbunit.org/框架用于存储单元测试的数据库,因此您不需要使用真实的数据库。

答案 2 :(得分:2)

我设法使用Spring / JUnit(不使用DBUnit)解决了这个问题。 简而言之,解决方案是在@BeforeClass中调用transactionManager.getTransaction(def).setRollbackOnly();

首先让我解释一下我的目的。 我的主要动机是这个流程:

1.开始交易
2.插入负载测试数据
3.在相同的测试数据上运行几个测试用例 4.回滚测试数据。

由于我在@BeforeClass中构建负载测试数据,因此我希望在@AfterClass中回滚。这似乎是不必要的,因为我可以简单地指示事务只在我的@BeforeClass中回滚!

所以我就是这样做的:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/spring/applicationContext-services-test.xml")
@TestExecutionListeners(inheritListeners = false, listeners = { SpecialDependencyInjectionTestExcecutionListener.class })
@TransactionConfiguration(defaultRollback = true)
@Transactional
public class loadTest {
...
private static HibernateTransactionManager transactionManager;
...

@BeforeClass
public static void setupDB() {
  //- set the transaction to rollback only. We have to get a new transaction for that.
  DefaultTransactionDefinition def = new DefaultTransactionDefinition();
  def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
  transactionManager.getTransaction(def).setRollbackOnly();
  ...
  //- start loading the data using the injected services.
  ...
}

这有助于在课程结束时回滚。

附: SpecialDependencyInjectionTestExcecutionListenerDependencyInjectionTestExecutionListener的扩展,我曾用它覆盖beforeTestClass,强制在调用@BeforeClass之前加载application.context。感谢Dmitriy强调这个倾听者,这是解决我心中想到的另一个问题的暗示。

感谢所有帮助突出显示的建议和建议,这些建议共同促成了我的解决方案。

Dhafir

答案 3 :(得分:0)

让我们假装你没有使用Spring。 (因为使用Spring,其他答案在这里更好。)那么你将有三个选择:

  1. 使用dbunit为您处理数据加载/清理工作。 (该网站目前正在关闭,但如果你谷歌,你可以看到一些教程。)
  2. 为手动更新创建手动删除
  3. 作为设置的第一步,在数据库中创建回滚点。这是how to do so in Oracle.

答案 4 :(得分:0)

查看How to load DBUnit test data once per case with Spring Test的已接受答案。所有测试完成后,您可以使用此技术执行数据库清理。