Débat : Comment testez-vous vos couches d'accès aux données ?

Le , par nico-pyright(c), Rédacteur
je reprends l'idée d'un billet que j'ai publié récemment afin de receuillir vos expériences.

C'est toujours difficile de tester sa DAL, j'ai trouvé plusieurs méthodes :

Ajouter, supprimer manuellement les données qui ont pu être supprimées, ajoutées à chaque test. Cela nécessite d'exécuter du sql en vrac à chaque test et peut être un travail laborieux et décourager le développeur quand les données sont nombreuses.

Restaurer un dump de la base de données de test après chaque exécution du test. Cela est très problématique si la base de données est volumineuse.

Avoir un moyen de mettre une base de données de test dans un certain état à chaque début de test (Unit Testing the Data Access Layer, par Tim Stall, Get Test Infected with NUnit: Unit Test Your .NET Data Access Layer, par Steven A. Smith). Cela nécessite un gros travail pour mettre sa base en état (construction de script sql pour vider la base, construire la structure, ajouter les données, etc ...) et un temps non négligeable d'exécution à chaque test. Cela peut aussi être gênant lorsqu'on travaille à plusieurs sur la même base de test.

Avoir une base de données de test et exécuter chaque opération CRUD dans une transaction qui sera ensuite annulée. Cela nécessite de rajouter du code spécifique dans nos tests pour créer et annuler la transaction.

Utiliser COM+ entreprise services (ou COM+ 1.5) et utiliser une classe de base pour ses tests qui encapsule la création et l'annulation de la transaction (Simplify Data Layer Unit Testing using Enterprise Services de Roy Osherove). Cela nécessite d'avoir un provider ADO.NET qui supporte les transactions distribuées, ce qui est quand même le cas de bon nombre d'entre eux et nécessite d'exécuter que des commandes sql qui peuvent être utilisées dans une transaction distribuée.

Des frameworks de test (MbUnit, XtUnit, NunitX) semblent utiliser des attributs à poser sur ses tests pour effectuer la restauration des données altérées)

Et vous, comment testez-vous vos DAL ?
Avez vous testé l'une de ces méthodes ? Quels sont vos retour d'expérience ?


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse

Avatar de nico-pyright(c) nico-pyright(c) - Rédacteur https://www.developpez.com
le 16/10/2009 à 16:57
Citation Envoyé par nico-pyright(c)  Voir le message
Utiliser COM+ entreprise services (ou COM+ 1.5) et utiliser une classe de base pour ses tests qui encapsule la création et l'annulation de la transaction (Simplify Data Layer Unit Testing using Enterprise Services de Roy Osherove). Cela nécessite d'avoir un provider ADO.NET qui supporte les transactions distribuées, ce qui est quand même le cas de bon nombre d'entre eux et nécessite d'exécuter que des commandes sql qui peuvent être utilisées dans une transaction distribuée.

Pour ma part, j'ai testé cette solution qui est plutot efficace et pas trop compliqué à mettre en place.

Cette solution a quand même un gros inconvénient, c'est que pendant son temps d'exécution, elle bloque toutes les requetes select qui n'ont pas de (nolock), ou les insert/update. Et ceci pour tous les autres utilisateurs également. (sql server)
Avatar de nicorama nicorama - En attente de confirmation mail https://www.developpez.com
le 16/10/2009 à 17:55
Avoir une base de données de test et exécuter chaque opération CRUD dans une transaction qui sera ensuite annulée. Cela nécessite de rajouter du code spécifique dans nos tests pour créer et annuler la transaction.

Et quand il y a un problème, je rebascule une bdd propre. L'avantage est qu'on peut tester les effets de bord : un test A se passe mal, mais n'est pas détecté. Le test B suppose que tout était comme avant, mais ce qu'a engendré A fait planter B.

Bonjour le casse-tête pour trouver que c'est A le responsable. On corrige, on rajoute le test d'effet de bord qui aurait du être fait dans A et on repart au combat.
Avatar de nico-pyright(c) nico-pyright(c) - Rédacteur https://www.developpez.com
le 20/10/2009 à 9:49
quels sont les outils que vous utilisez pour remettre en état vos bases de données ?
Avatar de tyzef tyzef - Membre à l'essai https://www.developpez.com
le 20/10/2009 à 17:21
Citation Envoyé par nico-pyright(c)  Voir le message
et qu'avez vous répondu alors ?

Bah justement pas grand chose ... d'où l'intérêt que j'ai à suivre ce post.

Disons que nous utilisons JUnit sur nos couches DAO (Hibernate). Mais nous développons plusieurs versions en parallèles, les structure des tables changent régulièrement et nous courrons un peu ces temps ci alors ... la classique gestion du temps (c'est de l'argent) ... et nos tests ne sont plus cohérents avec la/les bases.

Actuellement 100% de nos tests automatisés sont en échec et aucune ressource n'est dispo pour mettre à jour les classes de tests.

sinon vu l'instabilité des bases du client sur certaines couches, je pencherais pour une restauration de données spécifiques aux tests de chaque versions ... mais la base est très volumineuse et les avenants durant les phases de développements et jusqu'à la livraison sont réguliers (sans parler du manque de place à stocker les dumps)

Bref ... pas vraiment de réponse adaptée ...

Question subsidiaire : quels sont les apports de DBUnit par rapport à JUnit ?
Avatar de Philippe Vialatte Philippe Vialatte - Expert éminent sénior https://www.developpez.com
le 20/10/2009 à 17:49
Ok, j'arrive un peu tard...

Pour les tests qui tapent la Db, on a une db de test, qui n'est accédée que par le serveur díntegration continue pour les tests d'integration. Les tests unitaires ne tapent pas la db.

Dans le projet courant, ca ne pose pas trop de pb de ne faire les tests d'integration que depuis le serveur d'integration continue, ils tournent tous les soirs, et une modif dans la base de dev doit etre reportee dans la base de test.
Avant de fair tourner les tests, on a une tache qui fait un backup de la bdd, et apres le test, un restore de la bdd..

Comme la base est (relativement) stable et que l'équipe est petite, ca passe...
Avatar de nico-pyright(c) nico-pyright(c) - Rédacteur https://www.developpez.com
le 20/10/2009 à 18:15
Citation Envoyé par Philippe Vialatte  Voir le message
Avant de fair tourner les tests, on a une tache qui fait un backup de la bdd, et apres le test, un restore de la bdd..

Tu utilises un outil pour ca ?

Citation Envoyé par tyzef
les structure des tables changent régulièrement

C'est vrai que c'est toujours un peu galère de maintenir différentes structures, avec une base de dev qui peut être facilement perturbée et une base de test qui ne reflete pas forcément la dev à un instant T
Avatar de Philippe Vialatte Philippe Vialatte - Expert éminent sénior https://www.developpez.com
le 20/10/2009 à 18:44
Tu utilises un outil pour ca ?

Nant + une tache custom

http://weblogs.sqlteam.com/billg/arc...restoredb.aspx
Avatar de Maniak Maniak - Membre éclairé https://www.developpez.com
le 21/10/2009 à 15:59
Citation Envoyé par Philippe Vialatte  Voir le message
Pour les tests qui tapent la Db, on a une db de test, qui n'est accédée que par le serveur díntegration continue pour les tests d'integration. Les tests unitaires ne tapent pas la db.

Dans le projet courant, ca ne pose pas trop de pb de ne faire les tests d'integration que depuis le serveur d'integration continue, ils tournent tous les soirs, et une modif dans la base de dev doit etre reportee dans la base de test.
Avant de fair tourner les tests, on a une tache qui fait un backup de la bdd, et apres le test, un restore de la bdd..

Pareil, sauf qu'au lieu d'un backup/restore, il y a un script de création de la structure de la base et un autre pour insérer les données de référence (le minimum vital pour que la base soit utilisable quoi). NAnt aussi.
L'utilisation d'un script pour la structure a un avantage en parallèle qui est d'historiser l'évolution de la structure en permettant d'utiliser des outils comme SQLCompare pour synchroniser ces évolutions vers la base de qualif/préprod/production sans avoir à tout faire à la main.

Les tests d'intégration sont dans un projet séparé et sont lancés par le serveur d'intégration à intervalle régulier (toutes les 4h pour le moment), sur une base dédiée, recréée pour l'occasion. Ils sont exécutables aussi sur les postes de développeurs, du moment qu'ils ont au moins un SQLServer Express en local. Pour eux, il y a un 'test' explicite qui se charge de recréer la base de test en local, quand la structure ou que les données de référence changent, histoire que tout puisse se faire directement depuis VS.

Toutes les classes de test correspondantes dérivent d'une même base qui ouvre une transaction dans le [SetUp] et fait un rollback dans le [TearDown]. La classe de base expose un dérivé de l'UnitOfWork normal pour prendre la main sur la gestion des transactions, comme ça c'est transparent pour le reste.

Vu que les tests d'intégration sont limités à l'exécution des requêtes elles-mêmes (les Repositories concrets utilisant NHibernate), les tests restent généralement très simples. Dès qu'il s'agit de tester autre chose qu'un Repository, ça se fait via des tests unitaires normaux avec de faux repositories, sans dépendance sur NHibernate.

L'option SQLite pourrait être plus rapide et permettre éventuellement de lancer les tests d'accès en même temps que les tests unitaires, mais j'aime autant qu'ils s'exécutent sur une plate-forme la plus proche possible de l'appli en prod

Pas essayé NDbUnit, mais ça me semble un peu de l'overkill quand on a déjà ce qu'il faut pour créer une base de test, que le mécanisme de transaction est facilement utilisable et qu'on a des repositories dispos pour insérer facilement les données de test à la demande.

(au final, merci DDD et NHibernate
Avatar de nico-pyright(c) nico-pyright(c) - Rédacteur https://www.developpez.com
le 22/10/2009 à 9:58
est-ce que vous avez déjà envisagé d'utiliser Visual Studio Database edition ?
Avatar de Immobilis Immobilis - Expert éminent https://www.developpez.com
le 10/11/2009 à 1:23
Salut,

Pour ce qui est de tester la DAL, j'ai une architecture 3-Tiers assez robuste. Du coup il suffit de suivre le modèle et ça roule. En plus de la DAL, j'ai un objet de connexion assez pratique. Je teste toujours sur la même base sans la remettre en l'état. Elle est trop grosse.

Il ne me semble pas qu'il y ait 36 façons d'implémenter le CRUD. Au final, les requêtes sont les mêmes. Si on utilise des procédures stockées, qu'on utilise pas trop de connections, des DataReader plutôt que des DataSet, ne pas poser de verrous sur les SELECT (sauf si nécessaire)... Un CRUD peut être testé sur une table simple. Une fois qu'il fonctionne bien cela dépend de l'architecture de la base, des modèles qu'elle représente. Certaines des tables de notre base contiennent plus de 250 champs! On ne pouvait pas aller au delà sous SQL Server 2000

Les tests qui m'ont permis d'atteindre le niveau de performance souhaité on tourné autour des compteurs de performance de windows des serveur IIS et SQL.

Ensuite c'est du bon sens, ne charger que les données dont on a besoin. L'architecture de la base a aussi un role à jouer (index, etc).

A+
Avatar de redsonic redsonic - Membre régulier https://www.developpez.com
le 12/11/2009 à 18:42
Citation Envoyé par Immobilis  Voir le message
Certaines des tables de notre base contiennent plus de 250 champs! On ne pouvait pas aller au delà sous SQL Server 2000

Woo,
Offres d'emploi IT
Expert décisionnel business intelligence H/F
Safran - Ile de France - Évry (91090)
Responsable transverse - engagement métiers H/F
Safran - Ile de France - Corbeil-Essonnes (91100)
Ingénieur intégration, validation, qualification du système de drone H/F
Safran - Ile de France - Éragny (95610)

Voir plus d'offres Voir la carte des offres IT
Responsable bénévole de la rubrique Microsoft DotNET : Hinault Romaric -