web-dev-qa-db-fra.com

Comment tester le code lié à la base de données avec NUnit?

Je veux écrire des tests unitaires avec NUnit qui ont atteint la base de données. J'aimerais avoir la base de données dans un état cohérent pour chaque test. Je pensais que les transactions me permettraient de "défaire" chaque test, j'ai donc cherché et trouvé plusieurs articles de 2004-05 sur le sujet:

Ceux-ci semblent résoudre le problème de l'implémentation d'un attribut personnalisé pour NUnit qui intègre la possibilité de restaurer les opérations de base de données après l'exécution de chaque test.

C'est super mais ...

  1. Cette fonctionnalité existe-t-elle quelque part dans NUnit en mode natif?
  2. Cette technique a-t-elle été améliorée au cours des 4 dernières années?
  3. Est-ce toujours le meilleur moyen de tester le code lié à la base de données?

Edit: ce n'est pas que je veuille tester mon DAL spécifiquement, c'est plutôt que je veux tester des morceaux de mon code qui interagissent avec la base de données. Pour que ces tests soient "sans contact" et répétables, ce serait génial si je pouvais réinitialiser la base de données après chacun.

De plus, je veux faciliter cela dans un projet existant qui n'a pas de lieu de test pour le moment. Pour cette raison, je ne peux pratiquement pas créer une base de données et des données à partir de zéro pour chaque test.

62
Michael Haren

NUnit a maintenant un attribut [Rollback], mais je préfère le faire d'une manière différente. J'utilise la classe TransactionScope . Il y a plusieurs façons de l'utiliser.

[Test]
public void YourTest() 
{
    using (TransactionScope scope = new TransactionScope())
    {
        // your test code here
    }
}

Étant donné que vous n'avez pas demandé à TransactionScope de valider, il sera automatiquement annulé. Cela fonctionne même si une assertion échoue ou si une autre exception est levée.

L'autre façon consiste à utiliser [SetUp] pour créer le TransactionScope et [TearDown] pour appeler Dispose dessus. Il supprime une certaine duplication de code, mais accomplit la même chose.

[TestFixture]
public class YourFixture
{
    private TransactionScope scope;

    [SetUp]
    public void SetUp()
    {
        scope = new TransactionScope();
    }

    [TearDown]
    public void TearDown()
    {
        scope.Dispose();
    }


    [Test]
    public void YourTest() 
    {
        // your test code here
    }
}

C'est aussi sûr que l'instruction using dans un test individuel car NUnit garantira que TearDown est appelé.

Cela dit, je pense que les tests qui atteignent la base de données ne sont pas vraiment des tests unitaires. Je les écris toujours, mais je les considère comme des tests d'intégration. Je les considère toujours comme apportant de la valeur. Je les utilise souvent pour tester le code LINQ to SQL. Je n'utilise pas le designer. J'écris à la main les DTO et les attributs. Je suis connu pour me tromper. Les tests d'intégration aident à détecter mon erreur.

72
Mike Two

Je suis juste allé dans un groupe d'utilisateurs .Net et le présentateur a dit qu'il avait utilisé SQLlite dans la configuration et le démontage des tests et utilisé l'option en mémoire. Il a dû falsifier un peu la connexion et détruire explicitement la connexion, mais cela donnerait une base de données propre à chaque fois.

http://houseofbilz.com/archive/2008/11/14/update-for-the-activerecord-quotmockquot-framework.aspx

4
nportelli

J'appellerais ces tests d'intégration, mais peu importe. Ce que j'ai fait pour ces tests, c'est que mes méthodes de configuration dans la classe de test effacent toutes les tables d'intérêt avant chaque test. En général, j'écris à la main le SQL pour le faire afin que je n'utilise pas les classes testées.

Généralement, je compte sur un ORM pour ma couche de données et donc je n'écris pas beaucoup de tests unitaires là-bas. Je ne ressens pas le besoin de tester le code unitaire que je n'écris pas. Pour le code que j'ajoute dans la couche, j'utilise généralement l'injection de dépendances pour extraire la connexion réelle à la base de données afin que lorsque je teste mon code, il ne touche pas la base de données réelle. Faites-le en conjonction avec un cadre moqueur pour de meilleurs résultats.

2
tvanfosson

Pour ce type de test, j'ai expérimenté avec NDbUnit (en collaboration avec NUnit). Si la mémoire est bonne, c'était un portage de DbUnit de la plate-forme Java. Il avait beaucoup de commandes lisses pour le genre de chose que vous essayez de faire. Le projet semble avoir bougé ici:

http://code.google.com/p/ndbunit/

(il était à http://ndbunit.org ).

La source semble être disponible via ce lien: http://ndbunit.googlecode.com/svn/trunk/

1
Scott Lawrence

Envisagez de créer un script de base de données afin de pouvoir l'exécuter automatiquement à partir de NUnit ainsi que manuellement pour d'autres types de tests. Par exemple, si vous utilisez Oracle, lancez SqlPlus depuis NUnit et exécutez les scripts. Ces scripts sont généralement plus rapides à écrire et plus faciles à lire. De plus, très important, l'exécution de SQL à partir de Toad ou équivalent est plus éclairante que l'exécution de SQL à partir de code ou à travers un ORM à partir de code. En général, je vais créer un script de configuration et de démontage et les mettre dans les méthodes de configuration et de démontage.

La question de savoir si vous devez parcourir la base de données à partir de tests unitaires est une autre discussion. Je pense qu'il est souvent logique de le faire. Pour de nombreuses applications, la base de données est le centre d'action absolu, la logique est fortement basée sur les ensembles, et toutes les autres technologies et langages et techniques passent des fantômes. Et avec l'essor des langages fonctionnels, nous commençons à réaliser que SQL, comme JavaScript, est en fait un excellent langage qui était là sous nos yeux toutes ces années.

En passant, Linq to SQL (que j'aime dans le concept mais que je n'ai jamais utilisé) me semble presque comme un moyen de faire du SQL brut à partir du code sans admettre ce que nous faisons. Certaines personnes aiment SQL et savent qu'elles l'aiment, d'autres l'aiment et ne savent pas qu'elles l'aiment. :)

0
Mike