Je n'ai aucun problème à tester mon DAO et mes services, mais lorsque je teste INSERT
s ou UPDATE
s, 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?
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 ... );
}
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 à
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.
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.