2010-11-12 123 views
34

我没有问题测试我的DAO和服务,但是当我测试INSERT s或UPDATE s我想回滚事务并且不影响我的数据库。如何在JUnit中使用Spring测试服务时回滚数据库事务?

我在我的服务中使用@Transactional来管理事务。我想知道,是否有可能知道事务是否可以正常工作,但回滚它以防止更改数据库?

这是我的测试:

@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(); 
     } 
    } 
} 

的问题是,这个测试将失败,因为事务已rollbacked,但插入是OK! 如果我删除@TransactionConfiguration(defaultRollback=true),则测试通过但新记录将插入到数据库中。

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

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

+0

很好的问题+1 :-) – 2013-12-13 10:52:48

回答

28

你需要事务边界延伸到你的测试方法的边界。您可以通过注释测试方法(或整个测试类)作为@Transactional做到这一点:

@Autowired SessionFactory sf; 

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

嗨,现在测试通过,但回滚被忽略。我有@Transactional通过“testAddPerson”和“addPerson”。 – blow 2010-11-12 17:11:32

+0

如果我从myService中删除@Transactional,那么测试中没有活动事务,所以我认为@Transactional在“testAddPerson”不起作用... – blow 2010-11-12 17:13:40

+5

@blow:我只注意到你已经扩展了AbstractJUnit38SpringContextTests。由于您使用'@ RunWith'进行JUnit 4测试,因此不需要它。 – axtavt 2010-11-12 17:29:41

2

退房

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

第8.3.4节特别

Spring有一些类进行测试,将包裹每个测试的交易,所以DB没有改变。如果你想要,你也可以改变这个功能。

编辑 - 根据您的更多相关信息,您可能想看看

AbstractTransactionalJUnit38SpringContextTests在

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

+0

嗨,我有更多的信息。 – blow 2010-11-12 16:56:23

+0

@blow - 我更新了我的答案。 – hvgotcodes 2010-11-12 17:01:01

+0

谢谢,这很有用,我在我的实现中发现了一个小问题。现在我有另一个问题,回滚被忽略 – blow 2010-11-12 17:14:58

0

如果:

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

您也可以使用这种方法来确保数据回滚之前正确写入你的

myService.addPerson("JUNIT"); 

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

1

使用下面的类之前注释:

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

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

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

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

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

添加您的代码中setUp()方法,这将在试验开始和最后的收官代码应放在teatDown()方法将在最后执行的执行。或者也可以使用@Before@After注释来代替它。