web-dev-qa-db-fra.com

Comment restaurer une transaction de base de données lors du test de services avec Spring dans JUnit?

Je n'ai aucun problème à tester mon DAO et mes services, mais lorsque je teste INSERTs ou UPDATEs, je veux annuler la transaction et ne pas affecter ma base de données.

J'utilise @Transactional Dans mes services pour gérer les transactions. Je veux savoir, est-il possible de savoir si une transaction se passera bien, mais l'annuler pour éviter de modifier la base de données?

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

Le problème est que ce test échouera car la transaction a été annulée, mais l'insertion est OK! Si je supprime @TransactionConfiguration(defaultRollback=true) alors le test réussit mais un nouvel enregistrement sera inséré dans la base de données.

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

Le test peut maintenant passer correctement, mais la restauration est ignorée et l'enregistrement est inséré dans la base de données. J'ai annoté la méthode addPerson() dans myService avec @Transactional, Évidemment. Pourquoi la restauration est-elle ignorée?

36
blow

Vous devez étendre les limites des transactions aux limites de votre méthode de test. Vous pouvez le faire en annotant votre méthode de test (ou toute la classe de test) comme @Transactional:

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

Vous pouvez également utiliser cette approche pour vous assurer que les données ont été correctement écrites avant la restauration:

@Autowired SessionFactory sf;

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

check-out

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

Section 8.3.4 en particulier

Spring a quelques classes de test qui encapsuleront chaque test dans une transaction, donc la base de données n'est pas modifiée. Vous pouvez également modifier cette fonctionnalité si vous le souhaitez.

Modifier - en fonction de vos informations, vous voudrez peut-être regarder

AbstractTransactionalJUnit38SpringContextTests à

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

2
hvgotcodes

Utilisez l'annotation suivante avant la classe:

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

ici txManager est le gestionnaire de transactions du contexte d'application.

Ici txManager est une instance ou un identifiant de bean du gestionnaire de transactions de 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" />

Ajoutez votre code dans la méthode setUp(), cela s'exécutera au début du test et le dernier code de fin devrait être placé dans la méthode teatDown() qui sera enfin exécutée. ou vous pouvez également utiliser l'annotation @Before et @After à la place.

1
user3145373 ツ

Si votre

myService.addPerson("JUNIT"); 

est annotée comme @Transactional, vous obtiendrez un type différent ou des erreurs en essayant de résoudre ce problème. Il vaut donc mieux tester les méthodes DAO.

0
Danylo Volokh