Quelles sont les conventions de dénomination les plus utilisées pour les tests unitaires? [fermé]

204

Général

  • Suivez les mêmes normes pour tous les tests.
  • Soyez clair sur ce qu'est chaque état de test.
  • Soyez précis sur le comportement attendu.

Exemples

1) MethodName_StateUnderTest_ExpectedBehavior

Public void Sum_NegativeNumberAs1stParam_ExceptionThrown() 

Public void Sum_NegativeNumberAs2ndParam_ExceptionThrown () 

Public void Sum_simpleValues_Calculated ()

Source: Normes de dénomination pour les tests unitaires

2) Séparer chaque mot par un trait de soulignement

Public void Sum_Negative_Number_As_1st_Param_Exception_Thrown() 

Public void Sum_Negative_Number_As_2nd_Param_Exception_Thrown () 

Public void Sum_Simple_Values_Calculated ()

Autre

  • Terminer les noms de méthode avec Test
  • Démarrer les noms de méthode avec le nom de classe
piqué
la source

Réponses:

94

Je suis à peu près avec vous sur ce seul homme. Les conventions de dénomination que vous avez utilisées sont les suivantes:

  • Précisez ce qu'est chaque état de test.
  • Spécifique sur le comportement attendu.

De quoi avez-vous besoin de plus d'un nom de test?

Contrairement à la réponse de Ray, je ne pense pas que le préfixe Test soit nécessaire. C'est du code de test, nous le savons. Si vous devez le faire pour identifier le code, vous rencontrez des problèmes plus importants, votre code de test ne doit pas être mélangé avec votre code de production.

Quant à la longueur et à l'utilisation du trait de soulignement, son code de test , qui s'en soucie? Seuls vous et votre équipe le verrez, tant qu'il est lisible et clair sur ce que fait le test, continuez! :)

Cela dit, je suis encore assez nouveau pour tester et bloguer mes aventures avec ça :)

Rob Cooper
la source
20
Légère contradiction "tant qu'elle est lisible et claire" et "qui ... s'en soucie". Eh bien, tout le monde se soucie quand ce n'est pas lisible et clair, c'est pourquoi c'est important. :-)
David Victor
1
Un argument supplémentaire pour le préfixe. Lorsque vous recherchez un fichier dans IDE, vous pouvez facilement rechercher des cas de test en commençant par Testet le nom de votre classe. Si le nom de la classe et le nom de la classe de test sont identiques, nous devrons toujours faire une pause et lire le chemin de deux fichiers
CET UTILISATEUR A BESOIN D'AIDE
@THISUSERNEEDSHELP Je pense que votre point peut être facilement surmonté en ayant une bonne structure de dossiers comme src / libs & src / tests . Je sais que certains frameworks de test runners nécessitent un préfixe comme test pour l'identification du code de test, donc dans ces cas ne seront pas évités, mais pour le reste, il peut s'agir d'un préfixe répétitif sans requis .
negrotico19
@ negrotico19 Je pense au cas comme dans IntelliJ lorsque vous Search Everywhere(shift shift) ou Find a Class By Name(CMD O). Je comprends qu'il sera différencié par la structure des dossiers ou la structure des modules, mais lorsque nous recherchons quelque chose, nous savons déjà ce que nous voulons rechercher. Par exemple, si je recherche un test, je veux limiter ma recherche à testpuis rechercher le nom, plutôt que de rechercher le nom, puis filtrer le test manuellement par les yeux. C'est une petite distinction, mais il est beaucoup plus facile de «tester [nom de la classe]» et d'avoir un seul pop-up et de réduire la charge mentale
CET UTILISATEUR A BESOIN D'AIDE
37

Cela vaut également la peine d'être lu: Structuration des tests unitaires

La structure a une classe de test par classe testée. Ce n'est pas si inhabituel. Mais ce qui m'était inhabituel, c'est qu'il avait une classe imbriquée pour chaque méthode testée.

par exemple

using Xunit;

public class TitleizerFacts
{
    public class TheTitleizerMethod
    {
        [Fact]
        public void NullName_ReturnsDefaultTitle()
        {
            // Test code
        }

        [Fact]
        public void Name_AppendsTitle()
        {
            // Test code
        }
    }

    public class TheKnightifyMethod
    {
        [Fact]
        public void NullName_ReturnsDefaultTitle()
        {
            // Test code
        }

        [Fact]
        public void MaleNames_AppendsSir()
        {
            // Test code
        }

        [Fact]
        public void FemaleNames_AppendsDame()
        {
            // Test code
        }
    }
}

Et voici pourquoi:

Eh bien pour une chose, c'est une bonne façon de garder les tests organisés. Tous les tests (ou faits) d'une méthode sont regroupés. Par exemple, si vous utilisez le raccourci CTRL + M, CTRL + O pour réduire les corps de méthode, vous pouvez facilement analyser vos tests et les lire comme une spécification pour votre code.

J'aime aussi cette approche:

MethodName_StateUnderTest_ExpectedBehavior

Alors peut-être vous adapter à:

StateUnderTest_ExpectedBehavior

Parce que chaque test sera déjà dans une classe imbriquée

Lucifer
la source
2
Pour ceux qui utilisent le lanceur de test de Resharper dans Visual Studio, ils ont corrigé des bogues en utilisant des classes de test imbriquées dans 8.x. Depuis lors, cela est devenu de loin ma structure préférée.
angularsen
Est-il important que le nom devienne vraiment long avec l'approche MethodName_StateUnderTest_ExpectedBehavior? Tels que "InitializeApiConfiguration_MissingApiKey_IllegalArgumentException". Est-ce vraiment un bon nom de test?
portfoliobuilder
28

J'ai tendance à utiliser la convention de MethodName_DoesWhat_WhenTheseConditionssorte par exemple:

Sum_ThrowsException_WhenNegativeNumberAs1stParam

Cependant, ce que je vois beaucoup, c'est que le nom du test suive la structure de test unitaire de

  • Organiser
  • Acte
  • Affirmer

Qui suit également la syntaxe BDD / Gherkin de:

  • Donné
  • Quand
  • ensuite

qui serait de nommer le test à la manière de: UnderTheseTestConditions_WhenIDoThis_ThenIGetThis

donc à votre exemple:

WhenNegativeNumberAs1stParam_Sum_ThrowsAnException

Cependant, je préfère de loin mettre le nom de la méthode en cours de test, car les tests peuvent ensuite être organisés par ordre alphabétique ou apparaître par ordre alphabétique dans la liste déroulante des membres de VisStudio, et tous les tests pour 1 méthode sont regroupés.


Dans tous les cas, j'aime séparer les principales sections du nom du test par des traits de soulignement, par opposition à chaque mot , car je pense que cela facilite la lecture et la compréhension du point du test.

En d'autres termes, j'aime: Sum_ThrowsException_WhenNegativeNumberAs1stParammieux que Sum_Throws_Exception_When_Negative_Number_As_1st_Param.

CodingWithSpike
la source
22

Je nomme mes méthodes de test comme d'autres méthodes utilisant "PascalCasing" sans aucun soulignement ni séparateur. Je laisse le test postfix pour la méthode, car il n'ajoute aucune valeur. Le fait que la méthode soit une méthode de test est indiqué par l'attribut TestMethod .

[TestMethod]
public void CanCountAllItems() {
  // Test the total count of items in collection.
}

Étant donné que chaque classe de test ne doit tester qu'une autre classe, je laisse le nom de la classe hors du nom de la méthode. Le nom de la classe qui contient les méthodes de test est nommé comme la classe sous test avec le suffixe "Tests".

[TestClass]
public class SuperCollectionTests(){
    // Any test methods that test the class SuperCollection
}

Pour les méthodes qui testent les exceptions ou les actions qui ne sont pas possibles, je préfixe la méthode de test avec le mot Cannot .

[TestMethod]
[ExpectedException(typeOf(ArgumentException))]
public void CannotAddSameObjectAgain() {
  // Cannot add the same object again to the collection.
}

Mes convictions de dénomination sont basées sur l'article "TDD Tips: Test Naming Conventions & Guidelines" de Bryan Cook. J'ai trouvé cet article très utile.

Jehof
la source
1
+1 pour le lien vers mon message - bien qu'il ne soit pas nécessaire d'utiliser un préfixe "Test" dans vos tests. Assurez-vous que vos tests spécifient le comportement attendu. Par exemple, CanRetrieveProperCountWhenAddingMultipleItems ()
bryanbcook
2
Je ne l'aime pas car il n'inclut pas le comportement attendu
Johannes Rudolph
5

Le premier ensemble de noms est plus lisible pour moi, car le CamelCasing sépare les mots et les barres inférieures séparent les parties du schéma de nommage.

J'ai également tendance à inclure "Test" quelque part, soit dans le nom de la fonction, soit dans l'espace de noms ou la classe qui l'entoure.

Frank Szczerba
la source
2
@Frank methodName = camelCase MethodName = PascalCase
Metro Smurf
@ metro-smurf: distinction intéressante, je n'ai jamais entendu le terme PascalCase utilisé, et je le fais depuis longtemps. Je vois seulement le terme PascalCase apparaître dans les cercles de développeurs Microsoft, c'est ce que vous faites?
Frank Szczerba
Histoire autour de Pascal Casing et Camel Casing (de: Brad Abrams - blogs.msdn.com/brada/archive/2004/02/03/67024.aspx ) ... "Dans la conception initiale du Framework, nous avions des centaines d'heures de débat sur le style de nommage. Pour faciliter ces débats, nous avons inventé un certain nombre de termes. Avec Anders Heilsberg (le concepteur d'origine de Turbo Pascal) un membre clé de l'équipe de conception, il n'est pas étonnant que nous avons choisi le terme Pascal popularisé par le langage de programmation Pascal. "
Heliac
-3

Tant que vous suivez une seule pratique, cela n'a pas vraiment d'importance. Généralement, j'écris un test unitaire unique pour une méthode qui couvre toutes les variations d'une méthode (j'ai des méthodes simples;) puis j'écris des ensembles de tests plus complexes pour les méthodes qui en ont besoin. Ma structure de nommage est donc généralement testée (un maintien de JUnit 3).

Munger
la source
-8

J'utilise un préfixe «T» pour tester les espaces de noms, les classes et les méthodes.

J'essaie d'être soigné et de créer des dossiers qui répliquent les espaces de noms, puis de créer un dossier de tests ou un projet séparé pour les tests et de répliquer la structure de production pour les tests de base:

AProj
   Objects
      AnObj
         AProp
   Misc
      Functions
         AFunc
   Tests
      TObjects
         TAnObj
            TAnObjsAreEqualUnderCondition
      TMisc
         TFunctions
            TFuncBehavesUnderCondition

Je peux facilement voir que quelque chose est un test, je sais exactement à quel code d'origine il se rapporte (si vous ne pouvez pas le résoudre, le test est de toute façon trop compliqué).

Cela ressemble à la convention de dénomination des interfaces, (je veux dire, vous ne vous confondez pas avec des choses commençant par «I», ni avec «T»).

Il est facile de compiler simplement avec ou sans les tests.

C'est bon en théorie de toute façon, et fonctionne plutôt bien pour les petits projets.

user566399
la source
3
Approche intéressante. Certaines personnes peuvent soutenir que le préfixe T entre en conflit avec la convention que vous utilisez dans les génériques (par exemple, func (T1, T2, TResult)), mais personnellement, je m'en fiche tant qu'il y a un consensus au sein de l'équipe. Les noms sont courts, ce qui rend les choses plus lisibles aussi.
piqué le
Trop hongrois (notation) pour moi. De plus, comme indiqué, le préfixe T est utilisé pour les paramètres de type génériques.
Danny Varod
Je suis d'accord, la notation hongroise a été dépréciée et en raison du conflit avec les paramètres de type générique standard, je ne vois pas d'exception s'appliquer dans ce cas (comme il y en a pour les interfaces).
SonOfPirate