3

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

我正在使用 @BeforeClass 为几个测试用例准备我的 HSQL DB。然后我想在@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 中进行回滚的最佳方法有什么想法吗?

谢谢大家..

4

4 回答 4

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 {
于 2012-07-08T22:52:10.973 回答
3

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

您可以使用 spring 测试运行器来注释您的类和回滚事务

@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/框架用于为单元测试存根数据库,因此您不需要使用真正的数据库。

于 2012-07-08T22:53:14.100 回答
2

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

让我先解释一下我想做什么。我的主要动机是围绕这个流程:

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.
  ...
}

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

PS 这SpecialDependencyInjectionTestExcecutionListenerDependencyInjectionTestExecutionListener我用来覆盖 beforeTestClass 以强制在调用 @BeforeClass 之前加载 application.context 的扩展。归功于 Dmitriy 强调了这个 Listener,这是解决我脑海中另一个问题的提示。

感谢所有帮助突出显示和建议的人,这些人共同引导我找到了这个解决方案。

达菲尔

于 2012-07-09T23:12:53.490 回答
0

假设您没有使用 Spring。(因为使用 Spring,这里的其他答案更好。)然后您将有三个选择:

  1. 使用dbunit为您处理数据加载/清理。(该网站目前已关闭,但如果您谷歌它,您可以看到一些教程。)
  2. 为手动更新创建手动删除
  3. 在您的数据库中创建一个回滚点作为设置的第一步。这是在 Oracle 中执行此操作的方法。
于 2012-07-09T03:14:28.927 回答