Meilleures pratiques de dénomination des tests unitaires [clôturé]

564

Quelles sont les meilleures pratiques pour nommer les classes de test unitaire et les méthodes de test?

Cela a été discuté sur SO avant, à Quelles sont les conventions de dénomination populaires pour les tests unitaires?

Je ne sais pas si c'est une très bonne approche, mais actuellement dans mes projets de test, j'ai des mappings un à un entre chaque classe de production et une classe de test, par exemple Productet ProductTest.

Dans mes classes de test, j'ai ensuite des méthodes avec les noms des méthodes que je teste, un trait de soulignement, puis la situation et ce à quoi je m'attends, par exemple Save_ShouldThrowExceptionWithNullName().

James Newton-King
la source
Voir ici: stackoverflow.com/questions/96297/…
Point-virgule oublié
1
Cela ne répond pas à votre question, mais mérite d'être lu: haacked.com/archive/2012/01/02/structuring-unit-tests.aspx
Robs
3
Le guide de style de Google indique :,test<MethodUnderTest>_<state> par exemple testPop_emptyStack google-styleguide.googlecode.com/svn/trunk/javaguide.html 5.2.3 Noms de méthode. En cas de doute, suivez Google.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
@CiroSantilli 六四 事件 法轮功 包 卓 轩 Et la phrase suivante dit: "Il n'y a pas de méthode correcte pour nommer les méthodes de test". Allez comprendre.
user2418306
1
Je préfère toujours la recommandation de Phil Haack même des années plus tard.
pimbrouwers

Réponses:

524

J'aime la stratégie de nommage de Roy Osherove , c'est la suivante:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Il contient toutes les informations nécessaires sur le nom de la méthode et de manière structurée.

L'unité de travail peut être aussi petite qu'une méthode unique, une classe ou aussi grande que plusieurs classes. Il doit représenter toutes les choses qui doivent être testées dans ce cas de test et qui sont sous contrôle.

Pour les assemblages, j'utilise la .Teststerminaison typique , qui je pense est assez répandue et la même chose pour les classes (se terminant par Tests):

[NameOfTheClassUnderTestTests]

Auparavant, j'utilisais Fixture comme suffixe au lieu de Tests, mais je pense que ce dernier est plus courant, puis j'ai changé la stratégie de dénomination.

Marc Climent
la source
228
Pour moi, cela n'a aucun sens de mettre le nom de la méthode dans la méthode de test. Et si vous renommez la méthode? Aucun outil de refactoring ne renommera les tests pour vous. Finalement, vous finissez par renommer les méthodes de test à la main ou plus probablement par des tests mal nommés. C'est comme avec des commentaires. Trop, c'est pire que de ne pas commenter le code du tout.
Piotr Perak
80
@Peri, je pense que c'est un compromis. D'une part, les noms de vos tests peuvent devenir obsolètes, d'autre part, vous ne pouvez pas dire quelle méthode votre test teste. Je trouve que ce dernier revient beaucoup plus souvent.
Joel McBeth
15
Pour ajouter au commentaire de Peri - toutes les méthodes sont responsables d'une action, par exemple UpdateManager.Update(). Ayant cela à l'esprit, j'ai tendance à appeler mes tests WhenUpdating_State_Behaviourou WhenUpdating_Behaviour_State. De cette façon, je teste une action particulière d'une classe tout en évitant de mettre un nom de méthode dans un nom de test. Mais la chose la plus importante est que je dois avoir une idée de la logique métier qui échoue quand je vois le nom d'un test qui échoue
Ramunas
8
Resharper et IntelliJ trouveront probablement votre méthode de test et vous proposeront de la renommer si vous refactorisez / renommez à l'aide de ces outils. Essayez également de regarder dans les commentaires où vous mentionnez le nom de la méthode et de les mettre à jour également.
Jeff Martin
62
Les bons noms de méthode sont souvent les mêmes que l'action exécutée par la méthode. Si vous devez décider entre nommer votre test après votre méthode ou l'action que la méthode effectue, cela peut être un indice, vous devez renommer votre méthode . (Pas dans tous les cas cependant)
Kaadzia
121

J'aime suivre la norme de dénomination «Devrait» pour les tests tout en nommant le banc d'essai après l'unité sous test (c'est-à-dire la classe).

Pour illustrer (en utilisant C # et NUnit):

[TestFixture]
public class BankAccountTests
{
  [Test]
  public void Should_Increase_Balance_When_Deposit_Is_Made()
  {
     var bankAccount = new BankAccount();
     bankAccount.Deposit(100);
     Assert.That(bankAccount.Balance, Is.EqualTo(100));
  }
}

Pourquoi "Devrait" ?

Je trouve que cela oblige les rédacteurs du test à nommer le test avec une phrase du type "Devrait [être dans un état] [après / avant / quand] [l'action a lieu]"

Oui, écrire «devrait» partout devient un peu répétitif, mais comme je l'ai dit, cela oblige les écrivains à penser correctement (cela peut donc être bon pour les novices). De plus, cela donne généralement un nom de test anglais lisible.

Mise à jour :

J'ai remarqué que Jimmy Bogard est aussi un fan de 'should' et a même une bibliothèque de tests unitaires appelée Should .

Mise à jour (4 ans plus tard ...)

Pour les personnes intéressées, mon approche des tests de nommage a évolué au fil des ans. L'un des problèmes avec le modèle Should que je décris ci-dessus n'est pas facile à savoir en un coup d'œil quelle méthode est en cours de test. Pour OOP, je pense qu'il est plus logique de commencer le nom du test avec la méthode sous test. Pour une classe bien conçue, cela devrait aboutir à des noms de méthode de test lisibles. J'utilise maintenant un format similaire à <method>_Should<expected>_When<condition>. Évidemment, selon le contexte, vous voudrez peut-être remplacer les verbes Should / When par quelque chose de plus approprié. Exemple: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()

Jack Ukleja
la source
32
Peut-être même mieux et moins redondant, il suffit d' écrire une phrase qui dit ce qu'il fait, en supposant que les travaux d'essai: increasesBalanceWhenDepositIsMade().
hotshot309
3
Récemment, j'ai vu un article qui mentionnait une convention de dénomination similaire (j'aurais aimé la mettre en signet). Conçu pour rendre les listes de tests très lisibles lorsqu'elles sont triées par dispositif de test. Vous voyez quelque chose comme "BankAccount" puis sous celui-ci (sur différentes lignes) "Should_Increase_Balance_When_Deposit_Is_Made" "Should_Decrease_Balance_When_Withdrawal_Is_Made", etc.
Simon Tewsi
J'ai trouvé l'article. C'est dans le blog CodeThinked de Justin Etheredge Commencer à se moquer de Moq 3 - Partie 1 .
Simon Tewsi
11
J'utilise également Should and When mais dans l'autre sens. par exemple WhenCustomerDoesNotExist_ShouldThrowException (). Pour moi, cela a beaucoup plus de sens que Devrait alors Quand (c'est-à-dire dans un certain scénario, il devrait y avoir un certain résultat attendu). Cela correspond également à AAA (Arrange, Act, Assert) ... l'assertion est à la fin ... pas au début ;-)
bytedev
2
@Schneider: considérant "devrait" = "recommandé" puis facultatif, je me demande: ne serait-il pas préférable d'utiliser lexicalement "doit" = "doit" alors obligatoire / obligatoire. Par exemple, les RFC font la différence entre les deux. Il est donc recommandé ou nécessaire de réussir les tests?
blackwizard
79

J'aime ce style de dénomination:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

etc. Il montre clairement à un non-testeur quel est le problème.

Sklivvz
la source
63
mais @ hotshot309, il utilise peut-être .NET - Conventions de capitalisation .NET
Ace
2
@Ace, je suis totalement d'accord avec vous et je l'ai remarqué environ une minute après avoir posté ce commentaire. J'ai juré de l'avoir supprimé quand j'ai vu mon erreur, mais je suppose que je ne l'ai pas fait. Désolé pour ça.
hotshot309
3
@CoffeeAddict parce que les traits de soulignement dans les identifiants sont une <del> aberration </del> pas vraiment idiomatique en C #
Sklivvz
2
J'aime aussi éviter l'utilisation de shouldje préférerai willdoncOrdersWithNoProductsWillFail()
Calin
4
@Calin À mon avis, l'utilisation Willn'est pas vraiment appropriée et ce faisant, vous dites en fait à tort au lecteur qu'en aucun cas le test échouera ... si vous utilisez Willpour exprimer quelque chose dans le futur qui pourrait ne pas arriver, vous êtes l'utiliser de manière incorrecte alors que Shouldc'est le meilleur choix ici car cela indique que vous voulez / souhaitez que quelque chose se produise mais que cela ne soit pas ou ne puisse pas, lorsque le test s'exécute, il vous indique s'il a échoué / réussi, vous ne pouvez donc pas vraiment impliquer que au préalable, c'est l'explication logique, quelle est la vôtre? pourquoi évitez-vous Should?
Eyal Solnik
51

Kent Beck suggère:

  • Un appareil de test par «unité» (classe de votre programme). Les montages d'essai sont des classes elles-mêmes. Le nom du dispositif de test doit être:

    [name of your 'unit']Tests
    
  • Les cas de test (les méthodes de test) ont des noms comme:

    test[feature being tested]
    

Par exemple, avoir la classe suivante:

class Person {
    int calculateAge() { ... }

    // other methods and properties
}

Un appareil d'essai serait:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}
Sergio Acosta
la source
4
Je souhaite que plus de gens suivent ces directives. Il n'y a pas si longtemps, j'ai dû renommer plus de 20 méthodes de test car elles portaient des noms comme "ATest", "BasicTest" ou "ErrorTest".
Wedge
85
le préfixe de méthode de «test» ne devient-il pas redondant étant donné le suffixe de la classe?
Gavin Miller
50
N'oubliez pas que lorsque Kent a écrit ce livre. Les attributs n'ont pas été inventés. Par conséquent, le nom Test dans le nom de la méthode a indiqué au cadre de test que la méthode était un test. Beaucoup se sont également produits depuis 2002.
Thomas Jespersen
14
testCalculateAge ... c'est un nom sans signification pour votre méthode de test. "test" est redondant (nommez-vous toutes vos méthodes avec le préfixe "method"?). Le reste du nom n'a aucune condition en cours de test ou ce qui était attendu. CalculateAge est-elle la méthode testée? ..... qui sait ...
bytedev
1
Je voudrais ajouter que lors de l'utilisation de cette stratégie, une documentation est requise pour spécifier la sortie attendue. En guise de note complémentaire sur le préfixe «test»; certains frameworks de tests unitaires nécessitent des préfixes ou suffixes spécifiques pour reconnaître les tests. Préfixer les classes abstraites avec 'Abstract' n'est pas considéré comme redondant (parce que c'est auto-documenté), alors pourquoi cela ne s'applique-t-il pas avec 'Test'?
siebz0r
17

Noms de classe . Pour les noms d'appareils de test, je trouve que "Test" est assez courant dans le langage omniprésent de nombreux domaines. Par exemple, dans un domaine d'ingénierie: StressTestet dans un domaine cosmétique: SkinTest. Désolé d'être en désaccord avec Kent, mais utiliser "Test" dans mes montages de test ( StressTestTest?) Est déroutant.

"Unité" est également beaucoup utilisé dans les domaines. Par exemple MeasurementUnit. Une classe est-elle appelée MeasurementUnitTesttest de "Measurement" ou "MeasurementUnit"?

Par conséquent, j'aime utiliser le préfixe "Qa" pour toutes mes classes de test. Par exemple QaSkinTestet QaMeasurementUnit. Il n'est jamais confondu avec les objets de domaine, et l'utilisation d'un préfixe plutôt que d'un suffixe signifie que tous les appareils de test cohabitent visuellement (utile si vous avez des contrefaçons ou d'autres classes de support dans votre projet de test)

Espaces de noms . Je travaille en C # et je garde mes classes de test dans le même espace de noms que la classe qu'ils testent. C'est plus pratique que d'avoir des espaces de noms de test séparés. Bien sûr, les classes de test sont dans un projet différent.

Noms des méthodes de test . J'aime nommer mes méthodes WhenXXX_ExpectYYY. Il rend la condition préalable claire et aide à la documentation automatisée (à la TestDox). Ceci est similaire aux conseils du blog de test de Google, mais avec plus de séparation des conditions préalables et des attentes. Par exemple:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory
grundoon
la source
vous avez parlé des noms des méthodes de test et des noms des appareils de test. les noms des appareils de test sont mappés aux classes de production. où écrivez-vous le nom de la méthode de production dans votre test?
The Light
12

J'utilise le concept Given-When-Then . Jetez un œil à ce court article http://cakebaker.42dh.com/2009/05/28/given-when-then/ . L'article décrit ce concept en termes de BDD, mais vous pouvez également l'utiliser dans TDD sans aucune modification.

Pashec
la source
Given-When-Then est identique à MethodName_Scenario_ExpectedBehavior, n'est-ce pas?!
The Light
1
Pas exactement. Given_When_Then fait davantage référence à: GivenAnEntity_WhenSomeActionHappens_ThatResultIsExpected Le test doit exprimer la volonté de tester un comportement et non une implémentation .
plog17
1
"Given When Then" est souvent appelé Gherkin. C'est une DSL issue des outils Cucumber, JBehave et Behat.
bytedev
+1 c'est la meilleure méthode imo. Découpler comment une méthode fait quelque chose de ce que vous attendez du résultat est très puissant et évite beaucoup de problèmes décrits dans d'autres commentaires.
Lee
7

Je pense que l'une des choses les plus importantes est d'être cohérent dans votre convention de nommage (et d'accord avec les autres membres de votre équipe). Souvent, je vois des tas de conventions différentes utilisées dans le même projet.

bytedev
la source
7

J'ai récemment trouvé la convention suivante pour nommer mes tests, leurs classes et contenir des projets afin de maximiser leurs descriptifs:

Disons que je teste la Settingsclasse dans un projet dans l' MyApp.Serializationespace de noms.

Je vais d'abord créer un projet de test avec l' MyApp.Serialization.Testsespace de noms.

Dans ce projet et bien sûr l'espace de noms, je vais créer une classe appelée IfSettings(enregistrée sous IfSettings.cs ).

Disons que je teste la SaveStrings()méthode. -> Je nommerai le test CanSaveStrings().

Lorsque je lance ce test, il affiche l'en-tête suivant:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Je pense que cela me dit très bien ce qu'il teste.

Bien sûr, il est utile qu'en anglais le nom "Tests" soit le même que le verbe "tests".

Il n'y a pas de limite à votre créativité pour nommer les tests, de sorte que nous obtenons des titres de phrases complets pour eux.

Habituellement, les noms de test devront commencer par un verbe.

Les exemples comprennent:

  • Détecte (par exemple DetectsInvalidUserInput)
  • Jets (par exemple ThrowsOnNotFound)
  • Will (par exemple WillCloseTheDatabaseAfterTheTransaction)

etc.

Une autre option consiste à utiliser "cela" au lieu de "si".

Ce dernier me permet d'économiser des touches et décrit plus exactement ce que je fais, car je ne sais pas, que le comportement testé est présent, mais je teste s'il l'est.

[ Modifier ]

Après avoir utilisé la convention de dénomination ci-dessus pendant un peu plus longtemps maintenant, j'ai constaté que le préfixe If peut prêter à confusion lorsque vous travaillez avec des interfaces. Il se trouve que la classe de test IfSerializer.cs ressemble beaucoup à l'interface ISerializer.cs dans "Open Files Tab". Cela peut devenir très ennuyeux lors de la commutation entre les tests, la classe testée et son interface. En conséquence, je choisirais maintenant That plutôt que If comme préfixe.

De plus, j'utilise maintenant - uniquement pour les méthodes de mes classes de test car cela n'est pas considéré comme la meilleure pratique ailleurs - le "_" pour séparer les mots dans mes noms de méthode de test comme dans:

[Test] public void detects_invalid_User_Input()

Je trouve cela plus facile à lire.

[ Fin de l'édition ]

J'espère que cela donnera naissance à plus d'idées, car je considère que nommer les tests est très important car cela peut vous faire économiser beaucoup de temps qui aurait autrement été consacré à essayer de comprendre ce que font les tests (par exemple, après la reprise d'un projet après une interruption prolongée) .

Thorsten Lorenz
la source
2

Dans VS + NUnit, je crée généralement des dossiers dans mon projet pour regrouper les tests fonctionnels. Ensuite, je crée des classes d'appareils de test unitaire et je les nomme d'après le type de fonctionnalité que je teste. Les méthodes [Test] sont nommées selon les lignes suivantes Can_add_user_to_domain:

- MyUnitTestProject   
  + FTPServerTests <- Folder
   + UserManagerTests <- Test Fixture Class
     - Can_add_user_to_domain  <- Test methods
     - Can_delete_user_from_domain
     - Can_reset_password
Kev
la source
2

Je dois ajouter que le fait de conserver vos tests dans le même package mais dans un répertoire parallèle à la source testée élimine le ballonnement du code une fois que vous êtes prêt à le déployer sans avoir à faire un tas de modèles d'exclusion.

Personnellement, j'aime les meilleures pratiques décrites dans "JUnit Pocket Guide" ... c'est difficile de battre un livre écrit par le co-auteur de JUnit!

Steve Moyer
la source
3
Je ne crois pas que cela réponde réellement à la question posée - pourriez-vous faire un guide de poche JUnit d'édition et de réfraction? Merci!
Nate-Wilkins
0

le nom du cas de test pour la classe Foo doit être FooTestCase ou quelque chose comme ça (FooIntegrationTestCase ou FooAcceptanceTestCase) - puisqu'il s'agit d'un cas de test. voir http://xunitpatterns.com/ pour quelques conventions de dénomination standard comme test, cas de test, dispositif de test, méthode de test, etc.


la source