2009-01-30 5 views
15

J'ai créé des tests unitaires comme des fous et je trouve que je dois souvent mettre en place quelque chose dans un test que je viens de déchirer dans un test précédent. Est-il toujours raisonnable de créer quelque chose (par exemple un enregistrement de base de données) dans un test (par exemple un test d'insertion) et ensuite de l'utiliser pour un test ultérieur (par exemple un test de suppression)? Ou chaque test devrait-il toujours être complètement indépendant?Est-ce une mauvaise forme de compter sur l'ordre de vos tests unitaires NUnit

Pouvez-vous même déterminer l'ordre des tests dans NUnit ou sont-ils toujours effectués par ordre alphabétique?

Note: Je pose spécifiquement la question sur l'ordre des tests dans un fichier de test. Pas à travers les fichiers de test ou de toute façon plus globalement.

Mise à jour: Merci à tous ceux qui ont répondu - il y avait beaucoup de bonnes réponses et le sens du groupe est assez unanime. J'ai choisi la réponse de John Nolan car il a fourni l'explication la plus complète et beaucoup de liens. Comme vous l'avez peut-être deviné, j'ai été terriblement tenté d'enfreindre cette règle en pensant que cela pourrait être un peu "malodorant" comme l'a dit John. Merci également à Fortyrunner d'avoir ajouté le tag testeur.

+1

Bon travail pour rapporter et expliquer votre pensée mise à jour. Très agréable. –

+0

Merci, Jon. Je pense que c'est une communauté et que les communautés ont besoin d'un certain degré de soin pour grandir et s'épanouir. –

Répondre

10

Ceci est smelly

Une méthode de test plus propre consiste à ne dépendre que de la seule fonctionnalité dont vous voulez vérifier le comportement. Vous avez généralement besoin des autres objets dont vous avez besoin pour faire fonctionner votre méthode testée.

Une bonne façon de penser à l'approche des tests unitaires est le modèle Arrange, Act, Assert.

Ci-dessous un extrait de l'excellent eBook de Karl Seguin. J'ai annoté Arranger, Agir et Affirmer.

[TestFixture] public class CarTest 
{ 
    [Test] public void SaveCarCallsUpdateWhenAlreadyExistingCar() 
    { 
     //Arrange 
     MockRepository mocks = new MockRepository(); 
     IDataAccess dataAccess = mocks.CreateMock<IDataAccess>(); 
     ObjectFactory.InjectStub(typeof(IDataAccess), dataAccess); 
     //Act 
     Car car = new Car(); 
     Expect.Call(dataAccess.Save(car)).Return(389); 
     mocks.ReplayAll(); 
     car.Save(); 
     mocks.VerifyAll(); 
     // Assert 
     Assert.AreEqual(389, car.Id); 
     ObjectFactory.ResetDefaults(); 
    } 
} 
+0

L'instruction ObjectFactory.ResetDefaults() fait-elle réellement partie de 'Assertion'? J'y ai réfléchi, et je pense que cela devrait s'appeler Réorganiser, Agir, Affirmer, Nettoyer ou Réorganiser, Agir, Affirmer, Réinitialiser? Quelque chose de ce genre, ou peut-être: Arranger, Agir, Affirmer, Désarranger? –

+0

Bien que je sois d'accord avec vous, il y a des cas où un test doit simplement s'appuyer sur un autre et/ou l'utilisation d'objets simulés peut vaincre le point du processus de test. Un exemple serait une équipe qui exige que les fonctions soient divisées en parties plus discrètes que ce qui est raisonnable, ou lors des tests entre les versions de base de données. Dans ce cas, j'aime utiliser des variables statiques qui peuvent être initialisées, puis disponibles pour toutes les fonctions suivantes. – Brain2000

+0

@ Brain2000 Je dirais que ce ne sont pas des tests unitaires au sens traditionnel. Je ne suis pas tout à fait sûr de ce que vous entendez par «les fonctions doivent être divisées en parties plus discrètes que ce qui est raisonnable», mais dans ce dernier cas, vous semblez préférer les tests d'interaction/d'intégration. Il n'y a rien de mal à cela, mais ils effectuent des tâches différentes. –

3

Je ne comptais vraiment pas sur la commande de tests. Au lieu de cela, je voudrais tirer le code d'installation commun dans une méthode distincte et l'appeler à la fois du test simple et le plus compliqué. Vous pouvez également appeler le test d'insertion lui-même au début du test de suppression.

6

Je considérerais chaque test comme complètement indépendant de tout autre test. Même si vous pouviez mandater l'ordre des tests, ce serait un cauchemar de maintenance quand les tests devraient changer.

11

Regardez dans test fixture setups qui vous permet de spécifier les fonctions qui seront exécutées avant l'un des tests dans l'appareil. Cela vous permet de faire une configuration commune une fois et il sera toujours exécuté, que vous exécutiez un test ou tous les tests de la suite.

2

Malheureusement, l'ordre d'exécution du test unitaire n'est pas prévisible ou pourrait au moins être modifié à l'avenir. Par exemple. Le cadre de test unitaire sera modifié de sorte que chaque test sera exécuté dans un thread séparé. Donc, de mon point de vue, l'utilisation de l'ordre de test n'est pas raisonnable. D'autre part, vous pouvez créer un ensemble de petits tests indépendants pour tester de petites parties de votre code, puis créer un ou plusieurs grands tests qui exécuteront vos petits tests dans un ordre spécifique.

8

Les tests unitaires sont conçus pour être autonomes et ne doivent pas être exécutés en tant que script séquentiel. Si vous en avez vraiment besoin, exécutez-les en une seule fois.

Si vos tests unitaires souffrent de expensive set-up, vous pouvez effectuer des tests d'intégration lorsque vous pensez effectuer des tests unitaires. Si vous utilisez une base de données SQL dans la plupart de vos tests unitaires, vous effectuez des tests d'intégration avec votre couche d'accès aux données.

3

Je vous recommande vivement de rendre tous vos tests unitaires indépendants. La logique de votre entreprise/structure de base de données etc. peut changer au fil du temps, de sorte que vous aurez éventuellement à remplacer ou à réécrire (ou même à rejeter) les tests unitaires existants - et si vous avez plusieurs autres tests en fonction de celui que vous 're remplaçant, cela pourrait causer des problèmes inutiles parce que vous auriez à passer par tous les autres tests ainsi et vérifier si ceux-ci fonctionnent toujours comme prévu.En outre, un test d'unité défaillant ne devrait pas être capable de faire glisser beaucoup d'autres (qui pourraient parfaitement fonctionner seuls) vers le bas. S'appuyer sur l'ordre de vos tests indique que vous persistez l'état à travers les tests.

2

Si vous avez des tests stateful (un problème commun avec le travail de base de données - qui est ce que je fais quand je ne suis pas sur le SO), il me semble que d'éviter l'ordre dans un fichier de test n'est pas absolument nécessaire . Cependant, vous devez reconnaître que si vous avez 2 tests, avec le test 2 en fonction du test 1, vous obtiendrez un échec double "catastrophique" si le test 1 échoue, car le test 2 n'a pas la configuration attendue (et, De plus, vous voulez vous inquiéter si le test 2 réussit après l'échec du test 1 si vous pensez que le test 2 dépend du passage du test 1).

C'est pourquoi vous voulez que les tests soient indépendants autant que possible - à la fois intra-fichier et inter-fichier.

Il serait très imprudent de dépendre de l'ordre entre (ensembles de) tests dans différents fichiers.