Java 在 JUnit 中使用 Spring 测试服务时如何回滚数据库事务?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4166983/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 12:14:45  来源:igfitidea点击:

How to rollback a database transaction when testing services with Spring in JUnit?

javahibernatespringtransactionsjunit

提问by blow

I have no problem testing my DAO and services, but when I test INSERTs or UPDATEs I want to rollback the transaction and not effect my database.

我测试我的 DAO 和服务没有问题,但是当我测试INSERTs 或UPDATEs 时,我想回滚事务而不影响我的数据库。

I'm using @Transactionalinside my services to manage transactions. I want to know, is it possible to know if a transaction will be fine, but rollback it to prevent altering database?

@Transactional在我的服务内部使用来管理交易。我想知道,是否有可能知道一个事务是否可以,但回滚它以防止更改数据库?

This is my Test:

这是我的测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/META-INF/spring.cfg.xml")
@TransactionConfiguration(defaultRollback=true)
public class MyServiceTest extends AbstractJUnit38SpringContextTests  {
    @Autowired
    private MyService myService;

    @BeforeClass
    public static void setUpClass() throws Exception {
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
    }

    @Test
    public void testInsert(){
        long id = myService.addPerson( "JUNIT" );
        assertNotNull( id );
        if( id < 1 ){
            fail();
        }
    }
}

The problem is that this test will fail because transaction was rollbacked, but the insert is OK! If I remove @TransactionConfiguration(defaultRollback=true)then the test pass but a new record will be inserted into database.

问题是这个测试会失败,因为事务被回滚了,但插入没问题!如果我删除@TransactionConfiguration(defaultRollback=true)然后测试通过但新记录将插入到数据库中。

@Test
@Transactional
@Rollback(true)
public void testInsert(){
    long id = myService.addPerson( "JUNIT" );
assertNotNull(id);
if( id < 1 ){
        fail();
    }
}

Now can test pass correctly, but rollback is ignored and the record is inserted into the database. I have annotated the method addPerson()inside myService with @Transactional, obviously. Why is the rollback being ignored?

现在可以正确测试通过,但忽略回滚并将记录插入到数据库中。显然,我已经用 注释了addPerson()myService 中的方法@Transactional。为什么回滚被忽略?

采纳答案by axtavt

You need to extend transaction boundaries to the boundaries of your test method. You can do it by annotating your test method (or the whole test class) as @Transactional:

您需要将事务边界扩展到测试方法的边界。您可以通过将您的测试方法(或整个测试类)注释为@Transactional

@Test 
@Transactional
public void testInsert(){ 
    long id=myService.addPerson("JUNIT"); 
    assertNotNull(id); 
    if(id<1){ 
        fail(); 
    } 
} 

You can also use this approach to ensure that data was correctly written before rollback:

您还可以使用这种方法来确保在回滚之前正确写入数据:

@Autowired SessionFactory sf;

@Test 
@Transactional
public void testInsert(){ 
    myService.addPerson("JUNIT"); 
    sf.getCurrentSession().flush();
    sf.getCurrentSession().doWork( ... check database state ... ); 
} 

回答by hvgotcodes

check out

查看

http://static.springsource.org/spring/docs/2.5.x/reference/testing.html

http://static.springsource.org/spring/docs/2.5.x/reference/testing.html

Section 8.3.4 in particular

特别是第 8.3.4 节

Spring has some classes for testing that will wrap each test in a transaction, so the DB is not changed. You can change that functionality if you want too.

Spring 有一些用于测试的类,它们将每个测试包装在一个事务中,因此数据库不会改变。如果您愿意,您也可以更改该功能。

Edit -- based on your more infos, you might want to look at

编辑 - 根据您的更多信息,您可能需要查看

AbstractTransactionalJUnit38SpringContextTests at

AbstractTransactionalJUnit38SpringContextTests 在

http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/context/junit38/AbstractTransactionalJUnit38SpringContextTests.html

http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/context/junit38/AbstractTransactionalJUnit38SpringContextTests.html

回答by Danylo Volokh

If your

如果你的

myService.addPerson("JUNIT"); 

method is annotated like @Transactional you will be getting some different kind or errors trying to fix this. So you better just test DAO methods.

方法被注释为 @Transactional 你会得到一些不同的类型或错误来解决这个问题。所以你最好只测试 DAO 方法。

回答by user3145373 ツ

Use Following annotation before class :

在上课前使用以下注释:

@TransactionConfiguration(transactionManager = "txManager",defaultRollback = true)
@Transactional

here txManageris application context's Transaction Manager.

txManager是应用程序上下文的事务管理器。

Here txManageris an instance or bean id of Transaction manager from application context.

txManager是来自 的事务管理器的实例或 bean id application context

<!-- Transaction Manager -->
    <bean id="txManager"
          class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:annotation-driven transaction-manager="txManager" />

Add your code inside setUp()method, this will execute in start of the test and the last wrap up code should be put in teatDown()method that will executed at last. or you can also use @Beforeand @Afterannotation instead of it.

setUp()方法中添加你的代码,这将在测试开始时执行,最后的包装代码应该放在teatDown()最后执行的方法中。或者您也可以使用@Before@After注释代替它。