2010-11-12 15 views
34

Non ho problemi a testare il mio DAO ei servizi, ma quando provo INSERT s o UPDATE s voglio eseguire il rollback della transazione e non influire sul mio database.Come eseguire il rollback di una transazione di database durante il test dei servizi con Spring in JUnit?

Sto utilizzando il servizio @Transactional all'interno dei miei servizi per gestire le transazioni. Voglio sapere, è possibile sapere se una transazione andrà bene, ma ripristinarla per evitare di alterare il database?

Questa è la mia prova:

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

Il problema è che questo test avrà esito positivo perché transazione è stata annullate da una rollback, ma l'inserto è OK! Se rimuovo @TransactionConfiguration(defaultRollback=true) il test pass ma un nuovo record verrà inserito nel database.

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

Ora il test può passare correttamente, ma il rollback viene ignorato e il record viene inserito nel database. Ho annotato il metodo addPerson() all'interno di myService con @Transactional, ovviamente. Perché il rollback viene ignorato?

+0

buona domanda +1 :-) –

risposta

28

è necessario estendere i confini delle transazioni per i confini della vostra metodo di prova. Puoi farlo annotando il vostro metodo di prova (o tutta la classe di test) come @Transactional:

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

È inoltre possibile utilizzare questo approccio per assicurare che i dati è stato scritto correttamente prima di rollback:

@Autowired SessionFactory sf; 

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

ciao, ora test pass, ma il rollback è stato ignorato. Ho @Transactional su "testAddPerson" e su "addPerson". – blow

+0

Se rimuovo @Transactional da myService, non c'è una transazione attiva per il test, quindi penso che @Transactional su "testAddPerson" non funzioni ... – blow

+5

@blow: Ho appena notato che hai "estendi AbstractJUnit38SpringContextTests". Non è necessario dal momento che hai un test JUnit 4 con '@ RunWith'. – axtavt

2

check out

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

sezione 8.3.4 in particolare

Primavera ha alcune classi per i test che vi avvolgerà ogni test in una transazione, in modo che il DB non viene modificato. Puoi cambiare questa funzionalità se vuoi anche tu.

Edit - sulla base di più le vostre informazioni, si potrebbe desiderare di guardare

AbstractTransactionalJUnit38SpringContextTests a

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

+0

ciao ho avuto più informazioni. – blow

+0

@blow - ho aggiornato la mia risposta. – hvgotcodes

+0

grazie, questo è utile, ho trovato un piccolo problema nella mia implementazione. Ora ho un altro problema, il rollback è ignorato – blow

0

Se il metodo di

myService.addPerson("JUNIT"); 

è annotato come @Transactional vi sarà sempre un qualche tipo diverso o errori cercando di risolvere questo problema. Quindi è meglio testare i metodi DAO.

1

Usa seguente annotazione prima classe:

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

qui txManager è Transaction Manager del contesto di applicazione.

Qui txManager è un'istanza o un bean ID di Transaction Manager da 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" /> 

aggiungere il codice all'interno setUp() metodo, questo verrà eseguito in inizio del test e l'ultimo involucro Codice dovrebbe essere messo in teatDown() metodo che eseguito alla fine. oppure puoi utilizzare l'annotazione @Before e @After invece di quella.

Problemi correlati