Developpez.com - Rubrique .NET

Le Club des Développeurs et IT Pro

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

Le 2009-10-16 10:05:29, 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 ?
  Discussion forum
20 commentaires
  • tyzef
    Membre à l'essai
    Tiens c'était justement la question de la réunion d'équipe aujourd'hui ... Ca tombe bien
  • et qu'avez vous répondu alors ?
  • LooserBoy
    Membre chevronné
    Envoyé par nico-pyright(c)

    Et vous, comment testez-vous vos DAL ?
    Avez vous testé l'une de ces méthodes ? Quels sont vos retour d'expérience ?
    En ce qui me concerne, deux méthodes ont été utilisées:
    - Restauration d'une base "propre" avant chaque test. Effectivement, cela est problématique avec une volumétrie importante. On avait limité le problème en ayant une base de test allégée en données (à 0% de matières grasses ).

    - Mettre la base de test partagée par l'équipe dans un état prédéterminé par script SQL pour se simplifier la tâche. C'est la méthode utilisée dans ma mission actuelle. On se "télescope" énormément entre nous. Mais compte tenu de la volumétrie très importante, on a pas mieux à proposer pour le moment.
  • Maximil ian
    Membre émérite
    J'ai expérimenté lors de récents projets une structure qui fonctionne pas mal :

    Branchement de la DAL sur une base en mémoire (style SQLite) lorsqu'on est dans un contexte de tests.

    Génération du schéma de base (ça se fait facilement avec un ORM comme NHibernate) et remplissage des données minimales à chaque lancement de testFixture.

    Après chaque test, rollback des modifications faites par le test.

    Au niveau perfs, la différence par rapport à un "vrai" SGBD sur le poste du développeur, et d'autant plus par rapport à une base mutualisée, est assez significative.

    Toutefois le temps d'exécution de ce genre de test reste tout de même élevé pour un projet conséquent, c'est pourquoi je pense qu'il faut essayer de limiter au maximum les tests unitaires qui interagissent avec la base de données. C'est d'autant plus vrai dans un contexte d'intégration continue ou les tests sont joués très régulièrement.
  • Plageman
    Membre régulier
    Pour ma part, avec une base Firebird:
    - la dll de test unitaires utilise Firebird Embedded, ce qui évite d'avoir besoin de firebird sur le serveur ou le poste de test, ou de gérer des bases de test pour plusieurs développeurs
    - pour chaque test le nécessitant, une copie de base vide de données (avec firebird c'est un fichier) est faite et un script d'insertion de données est exécuté.
    Cela permet aussi d'avoir les scripts des données de tests dans subversion par exemple et voir l'historique des modifications.

    Cette façon de faire ne ralentit pas de façon notable l'exécution des tests, mais nous n'avons pas une énorme base avec genre 400 tables, et le jeu de données inséré à chaque fois est celui minimum pour la réussite d'un petit ensemble de Tests.
    D'un autre coté, un base de test pour les test unitaires ne devrait pas être volumineuse ? (on ne teste pas les performances.)

    Edit :
    ah, c'est exactement la solution déconseillée par Maximilian
  • Maximil ian
    Membre émérite
    Envoyé par Plageman
    ah, c'est exactement la solution déconseillée par Maximilian
    Heu, je ne la déconseille pas, c'est un mal nécessaire De toute façon, pour tester la DAL (ce qui est le sujet original du thread) on ne peut pas y couper.

    Simplement un test unitaire qui n'a pas pour objet l'accès aux données lui-même devrait autant que faire se peut éviter toute dépendance à la couche d'accès aux données. Sinon il n'est plus vraiment unitaire, ça devient un test d'intégration.

    Easy to Setup

    How easily can I set up an environment to run the tests? If the answer is "not very," I might never get the tests running. As much as possible, decouple unit tests from external dependencies like databases and web services by using mocks or stubs. When you do test against an external dependency, the dependency better be setup correctly by the automated build.
    http://codebetter.com/blogs/jeremy.m...20/129552.aspx
  • cf1020
    Membre du Club
    Bonjour,
    Moi personnellement je programme depuis 1981 et avec les années, j'ai peaufiné une technique qui consiste a exéctuer une routine de testes à chaque lancement de l'application qui va mettoyer toutes les tables de la BD qui subissent des mouvements (insertion, update et delete), et ca fonctionne très très bien depuis une dizaine d'années maintenant.
  • Patriarch24
    Membre expérimenté
    En Java il existe une api, dbunit, qui sert justement à réaliser des tests unitaires et d'intégration pour les couches d'accès aux données. Peut-être en existe-t-il un équivalent pour .Net ?
  • ktechlab
    Membre du Club
    Dans notre entreprise nous utlisons NDbUnit pour cela.

    Baké Jc. BAKENEGHE
    Sofware Coordinator
    http://koossery-tech.fr
  • Envoyé par nico-pyright(c)
    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)