Réaliser ses tests d’intégration avec Spring Test DBUnit

Spring_framework

Spring Test DBUnit est une extension du module de test spring-test afin d'intégrer facilement le framework DBUnit. Il s'agit d'une extension officielle, écrite par l'un des principaux commiter officiel de Spring, Phill Web.

DbUnit fait partie des framework xUnit (PHPUnit, JUnit, etc.). Il permet en particulier de charger des données et éventuellement d'effectuer des opérations de vérification dessus.

Le framework spring inclut un module de test, spring-test, permettant de réaliser des tests d'intégration en démarrant un contexte spring pour réaliser les tests.

Sur des applications classiques, dont la source de données est une base de données, la combinaison des deux permet de réaliser des tests d'intégration sur de vraies données de tests de manière répétitive et automatisable.

Pour ce faire, rien de plus simple que de rajouter la dépendance vers l'extension au sein de votre projet maven:

<dependency>
	<groupId>com.github.springtestdbunit</groupId>
	<artifactId>spring-test-dbunit</artifactId>
	<version>1.2.1</version>
</dependency>
Dépendance sur l'extension DbUnit de spring

Considérons la classe suivante sur laquelle nous souhaiterions effectuer un test:

public class JdbcPersonRepository implements PersonRepository {
	private JdbcOperations jdbcOperations;

	public JdbcPersonRepository(final JdbcOperations jdbcOperations) {
		this.jdbcOperations = jdbcOperations;
	}

	@Override
	public Person findById(final Long idPerson) {
		return jdbcOperations.queryForObject("SELECT id, firstName, lastName FROM person WHERE id=?", (rs, i) -> new Person(rs.getLong("id"), rs.getString("firstName"), rs.getString("lastName")), idPerson);
	}
}
JdbcPersonRepository

On crée notre jeu de données très simplement en éditant le fichier suivant:

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
	<person id="1" firstName="fooFirstName" lastName="fooLastName" />
</dataset>
PersonRepositoryITCase.xml

Enfin notre classe de test:

@DbUnitConfiguration(dataSetLoader = FlatXmlDataSetLoader.class)
@SpringApplicationConfiguration(classes = { IntegrationTestConfiguration.class })
@TestExecutionListeners({ DbUnitTestExecutionListener.class })
@DatabaseSetup
@DatabaseTearDown
public class PersonRepositoryITCase extends AbstractJUnit4SpringContextTests {

	@Autowired private PersonRepository personRepository;

	public void testFindById() {
		final Person result = personRepository.findById(1L);
		Assert.assertNotNull(result);
		Assert.assertEquals(Long.valueOf(1), person.getId());
		Assert.assertEquals("fooFirstName", person.getFirstName());
		Assert.assertEquals("fooLastName", person.getLastName());
	}
}
PersonRepositoryITCase.java

La grande force de l'extension reste sa simplicité. Quand on regarde cette classe de test pour effectuer le bridge entre DbUnit et spring-test. En effet, il suffit de:

  1. Poser l'annotation @DbUnitConfiguration(dataSetLoader = FlatXmlDataSetLoader.class) si nos datasets sont au format flatXml.
  2. Activer le bridge à l'aide du listener à rajouter via l'annotation @TestExecutionListeners({ DbUnitTestExecutionListener.class }).
    A partir de ce moment là, l'extension est active.
  3. Monter notre jeu de données de tests à l'aide de l'annotation @DatabaseSetup.
    Par défaut, l'extension s'attend à récupérer le dataset au sein du même package que la classe de test et avec le même nom.
  4. Penser à démonter notre jeu de test à l'aide de l'annotation @DatabaseTearDown

Pour aller plus, n'hésitez pas à consulter la documentation qui présente plein d'autres fonctionnalités telles que la comparaison des données à l'aide de l'annotation  @ExpectedDatabase, ou encore la configuration personnalisée de DbUnit.

En conclusion, on peut voir que la mise en place de tests d'intégration avec des jeux de tests persistant est simple. Donc désormais, vous n'avez plus d'excuses pour ne plus les mettre en place sur vos projets respectifs !

4 commentaires

  1. Bonjour Patrice.
    Ce billet est très intéressant, j’ignorais que Spring s’était également ésaisi » de DbUnit.
    Cela dit, une petite coquille s’est glissée dans le liosting de la classe JdbcPersonRepository.
    Dans le constructeur JdbcPersonRepository(), le terme jdbcOper (t) ations est utiisé. Il me semble qu’un « t » s’est glissé sans y être forcément invité.

    Cordialement.

  2. Merci pour ce retour Georges. Effectivement une faute de frappe s’est glissée, je corrige right away.

    Bien cordialement,

  3. Bonjour,

    Merci pour cet exposé. J’ai cependant une question : comment est initialisé JdbcPersonRepository(final JdbcOperations jdbcOperations) ? Il y a un bean quelque part ? Si oui serait-il possible de l’avoir ?

    Merci par avance.

  4. Bonjour OnTheRoad,

    Effectivement JdbcPersonRepository est un bean. Tu as plusieurs possibilités:
    – via les annotations @Repository ou @Component (à ce moment là, ajouter @Inject ou @Autowired selon ta configuration)
    – via le fichier xml,
    – via une classe JAVA.

    Bonne journée !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.