2009-10-21 8 views
0

Je suis novice dans le domaine des tests unitaires et je pense que je me suis peut-être retrouvé dans un coin.Tests unitaires et clés primaires

Dans vos tests unitaires, quelle est la meilleure façon de gérer les clés primaires?

Espérons qu'un exemple va peindre un peu de contexte. Si créer plusieurs instances d'un objet (Lets 'say Person).

Mon test unitaire consiste à tester les relations correctes en cours de création.

Mon code est de créer Homer, il enfants Bart et Lisa. Il a aussi un ami Barney, Karl & Lenny.

J'ai séparé ma couche de données avec une interface. Ma préférence est de garder la clé primaire simple. Par exemple, sur Enregistrer, Person.ProductID = new Random(). Next (10000); au lieu de dire Barney.PersonID = 9110 Homer.PersonID = 3243 etc.

Peu importe la clé primaire, elle doit simplement être unique.

Des pensées?

EDIT:

Désolé, je ne l'ai pas fait clairement. Mon projet est configuré pour utiliser Dependency Injection. La couche de données est totalement séparée. L'objectif de ma question est: qu'est-ce qui est pratique?

+1

Générez-vous vos propres clés primaires? Ou autorisez-vous la DB à les générer pour vous? –

+1

La base de données le génère sur l'insertion –

Répondre

3

J'ai une classe appelée "Unique" qui produit des objets uniques (chaînes, entiers, etc.). Il s'assure qu'ils sont uniques par test en gardant un compteur statique interne. Cette valeur de compteur est incrémentée par clé générée et incluse dans la clé en quelque sorte.

Alors, quand je suis mise en place mon test

var Foo = { 
    ID = Unique.Integer() 
} 

J'aime qu'il communique que la valeur est importante pour ce test, tout le caractère unique.

J'ai une classe similaire 'Some' qui ne garantit pas l'unicité. Je l'utilise quand j'ai besoin d'une valeur arbitraire pour un test. C'est utile pour les énumérations et les objets d'entité.

Aucun d'entre eux est threadsafe ou quelque chose comme ça, c'est strictement son code de test.

+0

Cha-ching! C'est ce que j'étais après. Merci! –

0

Pourquoi utiliser des nombres aléatoires? Est-ce que la valeur numérique de la clé est importante? Je voudrais juste utiliser une séquence dans la base de données et appeler nextval.

1

Envisagez d'utiliser des GUID. Ils sont uniques dans l'espace et dans le temps, ce qui signifie que même si deux ordinateurs différents les ont générés au même moment, ils seront différents. En d'autres termes, ils sont garantis être uniques. Les nombres aléatoires ne sont jamais bons, il y a un risque considérable de collision.

Vous pouvez générer un Guid en utilisant la classe statique et méthode:

Guid.NewGuid(); 

En supposant qu'il est C#.

Edit:

Une autre chose, si vous voulez juste pour générer un grand nombre de données de test sans avoir à coder manuellement ou écrire un tas de boucles pour, regardez dans NBuilder. Il peut être un peu difficile de commencer (les méthodes fluentes avec chaînage de méthodes ne sont pas toujours meilleures pour la lisibilité), mais c'est un excellent moyen de créer une énorme quantité de données de test.

+0

L'utilisation de Guid serait trop lourde et je n'ai aucun contrôle sur le type de données. Mais je vais essayer NBuilder si! –

+0

L'utilisation de Guids est une pratique exemplaire émergente à l'ère des bases de données sur les produits de base et de la performance bon marché. Ce n'est plus exagéré. C'est juste trop long pour les jolies URL. – yfeldblum

+0

Si le seul avantage de la conversion de int à Guid est qu'un développeur peut tester une partie d'un système de production entier. Alors oui, je pense que c'est trop –

3

Il y a plusieurs coins possibles dans lesquels vous vous êtes plongé et qui pourraient vous mener à la question que vous vous posez.

  1. Peut-être que vous êtes inquiet au sujet réutilisant les clés primaires et écrasez ou chargement des données de manière incorrecte qui est déjà dans la base de données (par exemple, si vous testez contre une base de données de dev, par opposition à une base de données de test propre). Dans ce cas, je vous recommande de configurer vos tests unitaires pour créer les PK de leurs enregistrements en utilisant la séquence ou pour tester dans une base de données de test propre et dédiée.

  2. Peut-être que vous êtes préoccupé par l'efficacité de votre code avec PK au-delà d'un simple 1,2,3. Rassurez-vous, ce n'est pas quelque chose que l'on testerait normalement dans une application simple, car la plupart ne sont pas concernés par votre application: générer un nombre à partir d'une séquence est le problème du fournisseur de BD, garder la trace d'un numéro en mémoire le problème d'exécution/VM. Peut-être que vous essayez simplement d'apprendre ce que la meilleure pratique est pour ce genre de chose. Je vous suggère de configurer la base de données en insérant des enregistrements avant d'exécuter vos cas de test en utilisant les mêmes fonctionnalités que votre application elle-même utilisera pour insérer des enregistrements; Votre code d'application s'appuiera vraisemblablement sur un numéro de séquence géré par la base de données pour les PK, et si c'est le cas, utilisez-le. Enfin, après l'exécution de vos scénarios de test, vos tests doivent annuler toutes les modifications apportées à la base de données pour garantir que le test est idempotent sur plusieurs exécutions. C'est ma triste tentative de décrire un modèle de conception appelé test fixtures.

0

Le problème essentiel avec le test d'unité de base de données est que les clés primaires ne sont pas réutilisées. Au contraire, la base de données crée une nouvelle clé chaque fois que vous créez un nouvel enregistrement, même si vous supprimez l'enregistrement avec la clé d'origine.

Il existe deux façons de faire face à cela:

  1. Lire la primaire clé générée, à partir de la base de données et l'utiliser dans vos tests, ou
  2. Utilisez une nouvelle copie de la base de données chaque fois que vous tester.

Vous pouvez placer chaque test dans une transaction et renvoyer la transaction lorsque le test est terminé, mais les transactions de restauration ne fonctionnent pas toujours avec les clés primaires; le moteur de base de données ne réutilisera toujours pas les clés qui ont été générées une seule fois (dans SQL Server de toute façon).

0

Lorsqu'un test s'exécute sur une base de données via un autre morceau de code, il cesse d'être un test unitaire. C'est ce qu'on appelle un "integration test" parce que vous testez les interactions de différents morceaux de code et comment ils "s'intègrent" ensemble. Pas que ça compte vraiment, mais c'est amusant à savoir.

Lorsque vous effectuez un test, les choses doivent se produire:

  1. Prépare une transaction db
  2. Insérer connus (peut-être faux) articles de test/entités
  3. Appelez le (un et un seul) fonction à tester
  4. Testez les résultats
  5. Rollback la transaction

Ces choses devraient arriver pour chaque test. Avec NUnit, vous pouvez vous contenter d'écrire les étapes 1 et 5 juste une fois dans une classe de base, puis d'en hériter dans chaque classe de test. NUnit exécutera les méthodes décorées Setup et Teardown dans une classe de base.

À l'étape 2, si vous utilisez SQL, vous devrez écrire vos requêtes de sorte qu'elles renvoient les numéros PK à votre code de test.

INSERT INTO Person(FirstName, LastName) 
VALUES ('Fred', 'Flintstone'); 
SELECT SCOPE_IDENTITY(); --SQL Server example, other db vendors vary on this. 

Ensuite, vous pouvez le faire

INSERT INTO Person(FirstName, LastName, SpouseId) 
VALUES('Wilma', 'Flintstone', @husbandId); 
SET @wifeId = SCOPE_IDENTITY(); 

UPDATE Person SET SpouseId = @wifeId 
WHERE Person.Id = @husbandId; 
SELECT @wifeId; 

ou tout ce que vous avez besoin.

À l'étape 4, si vous utilisez SQL, vous devez sélectionner à nouveau vos données et tester les valeurs renvoyées.

Les étapes 2 et 4 sont moins compliquées si vous avez la chance de pouvoir utiliser un ORM décent comme (N) Hibernate (ou autre).

+0

Je n'ai pas besoin de tester la base de données. Je sais que cela fonctionne –