DbUnit

Un article de Agora2ia.


Sommaire

Présentation

DbUnit est un framework OpenSource créé par ManuelLaflamme qui vise à simplifier les TestUnitaires utilisant des BaseDeDonnees en Java. Pour se faire il étend JUnit : DbUnit s'utilise de la même façon, en écrivant des classes Java appelées TestCase.

Chaque test unitaire pourra définir dans un fichier XML les données qu'il souhaite voir figurer en base au début du test. DbUnit permet de facilement exporter un jeu de données d'une base pour créer ce fichier XML. Par contre, dans tous les cas, la structure de données (les tables) doit exister. Puis il pourra définir comment injecter ces données en base (ajoute, supprimer-tout-puis-ajoute...). DbUnit offre des méthodes utilitaires pour comparer l'état de la base de données en fin de test, notamment en comparant l'état final au contenu d'un second fichier XML qui lui contient les données attendues en base après le jeu du test. Enfin, après avoir jouer les tests, il est possible de remettre la base de données dans le même état qu'avant le jeu des tests.

DbUnit permet d'écrire des tests unitaires à la JUnit de façon à ce que chacun d'entre eux ait toujours le bon jeu de données en base : les tests unitaires avec des bases de données peuvent enfin être indépendants, ce qui est un des principes de base des tests unitaires.


Avantages

En résumé, DbUnit à l'avantage de :

  • Faciliter les opérations à chaque étapes du cycle de vie d'un test unitaire avec base de données.
  • Fournir un mécanisme simple pour charger des données de test reposant sur XML.
  • Permettre d'exporter facilement un jeu de données existant depuis une base de données vers un fichier XML.
  • Fonctionner avec de vastes dataset.
  • Faciliter la comparaison des données obtenues avec des valeurs attendues.
  • Fournir des méthodes pour comparer des données entre des fichiers plats, des requètes et des table de la base de données.


Pragmatic DbUnit

Configuration

  • Télécharger DbUnit
  • Dépendre des bonnes librairies


Créer un jeu de données


Ecrire un test

Créer le test

TODO : DBTestCase vs. DatabaseTestCase

  • Hériter de DatabaseTestCase
  • On peut surcharger
  • On peut surcharger la stratégie par défaut :
    • Pour l'initialisation de la base (getSetUpOperation() => DatabaseOperation.CLEAN_INSERT)
    • Pour la remise en ordre au sortir du test (and getTearDownOperation() => <tt>DatabaseOperation.NONE)
  • Surcharger les méthodes abstraites suivantes :
    • IDatabaseConnection getConnection() pour définir la connection à la base de données utilisée.
    • IDataSet getDataSet() pour charger le fichier de données XML que l'on souhaite utiliser.


Le scénario de test


Exécuter le test

  • Vider la base de données des anciennes données
  • Charger les données depuis le fichier XML
  • Jouer le test


Exemple de code

Le fichier données input.xml

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
    <login id="1" empcode="E005"
        loginname="chandan"
        password="chandan"
        loginenabled="y"/>
    <login id="2" empcode="E006"
        loginname="deepak" 
        password="deepak"
        loginenabled="n"/>
</dataset>


Le fichier test TestDbUnit.java

import java.sql.Connection;
import java.sql.DriverManager;
import org.dbunit.DatabaseTestCase;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;


public class TestDbUnit extends DatabaseTestCase {

	public static final String TABLE_LOGIN = "login";
	private FlatXmlDataSet loadedDataSet;

	// Provide a connection to the database
	protected IDatabaseConnection getConnection() throws Exception {
		Class.forName("com.mysql.jdbc.Driver");
		Connection jdbcConnection = DriverManager.getConnection(
				"jdbc:mysql://localhost:3306/hrapptest", "root", "root");
		return new DatabaseConnection(jdbcConnection);
	}

	// Load the data which will be inserted for the test
	protected IDataSet getDataSet() throws Exception {
		loadedDataSet = new FlatXmlDataSet(this.getClass().getClassLoader()
				.getResourceAsStream("input.xml"));
		return loadedDataSet;
	}

	// Check that the data has been loaded.
	public void testCheckLoginDataLoaded() throws Exception {
		assertNotNull(loadedDataSet);
		int rowCount = loadedDataSet.getTable(TABLE_LOGIN).getRowCount();
		assertEquals(2, rowCount);
	}
}


Notions avancées


Un peu de recul

Le format XML pour les données

Le fait que les données soient formalisées dans un fichier XML a ce double avantage de :

  1. Rendre le jeu de données plus lisible
  2. Mais aussi plus stable

que sous un autre format, tel que le CSV par exemple. Cependant cela à l'inconvénient d'augmenter dramatiquement la taille du fichier à mesure que le jeu de données augmente, le format XML étend plus verbeux qu'un format tabulaire tel que le CSV. Remarque, cela aurait donc tendance à pousser le développeur à réduire au maximum le jeu de données, et de supprimer les données inutiles... Ce qui une bonne pratique du test unitaire. C'est donc finalement un autre avantage ;o)¨


Ignoring some columns in comparison

http://dbunit.sourceforge.net/howto.html#assertdata


Notion d'héritage dans les dataset XML

Cela permet(rait) d'hériter d'un dataset existant, et de ne surcharger/définir que les données en plus ou différentes...

Cela facilite la lisibilité, la factorisation donc la maintenabilité.


Compatibilité avec JUnit4 ? =

Ressources