126 votes

Annulation de la transaction après @Test

Tout d'abord, j'ai trouvé beaucoup de fils de discussion sur StackOverflow à ce sujet, mais aucun d'entre eux ne m'a vraiment aidé, donc désolé de poser une question qui pourrait faire double emploi.

J'exécute des tests JUnit en utilisant spring-test, mon code ressemble à ceci

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {})
public class StudentSystemTest {

    @Autowired
    private StudentSystem studentSystem;

    @Before
    public void initTest() {
    // set up the database, create basic structure for testing
    }

    @Test
    public void test1() {
    }    
    ...  
}

Mon problème est que je veux que mes tests n'influencent PAS les autres tests. J'aimerais donc créer quelque chose comme un rollback pour chaque test. J'ai beaucoup cherché pour cela, mais je n'ai rien trouvé jusqu'à présent. J'utilise Hibernate et MySql pour cela.

174voto

Tomasz Nurkiewicz Points 140462

Il suffit d'ajouter @Transactional sur le dessus de votre test :

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {"testContext.xml"})
@Transactional
public class StudentSystemTest {

Par défaut, Spring va démarrer une nouvelle transaction autour de votre méthode de test et @Before / @After les rappels, en revenant en arrière à la fin. Cela fonctionne par défaut, il suffit d'avoir un gestionnaire de transactions dans le contexte.

De : 10.3.5.4 Gestion des transactions (en gras dans le texte) :

Dans le cadre de TestContext, les transactions sont gérées par le TransactionalTestExecutionListener. Notez que TransactionalTestExecutionListener es configuré par défaut même si vous ne déclarez pas explicitement @TestExecutionListeners sur votre classe de test. Cependant, pour permettre la prise en charge des transactions, vous devez fournir une classe de test PlatformTransactionManager dans le contexte de l'application chargée par @ContextConfiguration sémantique. En outre, vous devez déclarer @Transactional soit au niveau de la classe ou de la méthode pour vos tests .

23voto

user2418306 Points 1476

A part : La tentative d'amender la réponse de Tomasz Nurkiewicz a été rejetée :

Cette modification ne rend pas le message plus facile à lire, plus facile à trouver, plus précis ou plus accessible. Les modifications sont soit complètement superflues, soit nuisent activement à la lisibilité.


Correct et permanent enlace à la section pertinente de la documentation sur les tests d'intégration.

Pour permettre la prise en charge des transactions, vous devez configurer une PlatformTransactionManager haricot dans le ApplicationContext qui est chargé via @ContextConfiguration sémantique.

@Configuration
@PropertySource("application.properties")
public class Persistence {
    @Autowired
    Environment env;

    @Bean
    DataSource dataSource() {
        return new DriverManagerDataSource(
                env.getProperty("datasource.url"),
                env.getProperty("datasource.user"),
                env.getProperty("datasource.password")
        );
    }

    @Bean
    PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

De plus, vous devez déclarer la méthode de Spring @Transactional soit au niveau de la classe ou de la méthode pour vos tests.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Persistence.class, SomeRepository.class})
@Transactional
public class SomeRepositoryTest { ... }

Annoter une méthode d'essai avec @Transactional fait en sorte que le test soit exécuté dans une transaction qui sera, par défaut, automatiquement annulée à la fin du test. Si une classe de test est annotée avec @Transactional Si le test est exécuté dans le cadre d'une transaction, chaque méthode de test de cette hiérarchie de classes sera exécutée dans le cadre d'une transaction.

14voto

matt b Points 73770

Les réponses mentionnant l'ajout @Transactional sont corrects, mais pour plus de simplicité, vous pourriez simplement avoir votre classe de test extends AbstractTransactionalJUnit4SpringContextTests .

9voto

user2615724 Points 80

En plus d'ajouter @Transactional sur @Test vous devez également ajouter @Rollback(false)

5voto

Atul Kumbhar Points 913

Je sais, je suis trop tard pour poster une réponse, mais j'espère que cela pourra aider quelqu'un. De plus, je viens de résoudre le problème que j'avais avec mes tests. Voici ce que j'avais dans mon test :

Ma classe de test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "path-to-context" })
@Transactional
public class MyIntegrationTest 

Contexte xml

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="${jdbc.driverClassName}" />
   <property name="url" value="${jdbc.url}" />
   <property name="username" value="${jdbc.username}" />
   <property name="password" value="${jdbc.password}" />
</bean>

J'avais toujours le problème que la base de données n'était pas nettoyée automatiquement.

Le problème a été résolu lorsque j'ai ajouté la propriété suivante à BasicDataSource

<property name="defaultAutoCommit" value="false" />

J'espère que cela vous aidera.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X