Quelles sont les meilleures pratiques pour la désignation de classes de tests unitaires et de méthodes de test?
Ceci a été discuté sur SO auparavant, à Quelles sont les conventions de dénomination populaires pour les tests unitaires?
Je ne sais pas s'il s'agit d'une très bonne approche, mais actuellement, dans mes projets de test, j'ai des correspondances individuelles entre chaque classe de production et une classe de test, par exemple. Product
et 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()
.
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 seule méthode, une classe ou aussi grande que plusieurs classes. Il doit représenter tout ce qui doit être testé dans ce cas de test et est sous contrôle.
Pour les assemblages, j'utilise la terminaison typique .Tests
, qui est selon moi assez répandue et identique 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, alors j'ai changé la stratégie de nommage.
J'aime suivre les "Devrait" norme de dénomination pour les tests tout en nommant le dispositif de test après la unité sous test (c.-à-d. 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 auteurs du test à nommer le test avec une phrase du type "Devrait-il ê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, il en résulte généralement un nom de test en anglais lisible.
Mise à jour :
J'ai remarqué que Jimmy Bogard est aussi fan de "should" et possède même une bibliothèque de tests unitaires appelée Should .
Mise à jour (4 ans plus tard ...)
Pour ceux que ça intéresse, mon approche des tests de nommage a évolué au fil des ans. L'un des problèmes avec le motif Si je décris ci-dessus n'est pas facile de savoir d'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 testée. Pour une classe bien conçue, cela devrait donner des noms de méthodes de test lisibles. J'utilise maintenant un format similaire à <method>_Should<expected>_When<condition>
. Évidemment, selon le contexte, vous voudrez peut-être substituer les verbes Should/When à quelque chose de plus approprié. Exemple: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()
J'aime ce style de nommage:
OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();
etc. Le problème est clairement expliqué à un non-testeur.
Kent Beck suggère:
Un appareil de test par 'unité' (classe de votre programme). Les fixtures de test sont des classes elles-mêmes. Le nom du montage 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, ayant la classe suivante:
class Person {
int calculateAge() { ... }
// other methods and properties
}
Un appareil de test serait:
class PersonTests {
testAgeCalculationWithNoBirthDate() { ... }
// or
testCalculateAge() { ... }
}
Noms de classe. Pour les noms de matériel de test, je trouve que "Test" est assez courant dans le langage omniprésent de nombreux domaines. Par exemple, dans un domaine technique: StressTest
, et dans un domaine cosmétique: SkinTest
. Désolé de ne pas être d'accord avec Kent, mais utiliser "Test" dans mes montages de test (StressTestTest
?) Est source de confusion.
"Unité" est également beaucoup utilisé dans les domaines. Par exemple. MeasurementUnit
. Une classe appelée MeasurementUnitTest
est-elle un test de "Measurement" ou "MeasurementUnit"?
Par conséquent, j'aime utiliser le préfixe "Qa" pour toutes mes classes de test. Par exemple. QaSkinTest
et 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 montages de test cohabitent visuellement (utile si vous avez des faux 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'elles 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.
Nom des méthodes de test. J'aime nommer mes méthodes WhenXXX_ExpectYYY. Cela clarifie la condition préalable et facilite la documentation automatisée (à la manière de TestDox). Ceci est similaire aux conseils du blog de test de Google, mais avec une séparation accrue des conditions préalables et des attentes. Par exemple:
WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory
J'utilise le concept étant donné quand, alors . Jetez un oeil à 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.
Voir: http://googletesting.blogspot.com/2007/02/tott-naming-unit-tests-responsibly.html
Pour les noms de méthode de test, je trouve personnellement que l’utilisation de noms verbeux et auto-documentés est très utile (à côté des commentaires Javadoc qui expliquent davantage ce que fait le test).
J'ai récemment mis au point la convention suivante pour nommer mes tests, leurs classes et leurs projets afin de maximiser leur descriptive:
Disons que je teste la classe Paramètres dans un projet de la MyApp.Serialization espace de noms.
Tout d'abord, je vais créer un projet de test avec l'espace de noms MyApp.Serialization.Tests .
Dans ce projet et bien sûr dans l'espace de noms, je vais créer une classe appelée IfSettings (enregistrée sous le nom IfSettings.cs).
Disons que je teste la méthode SaveStrings () . -> Je vais nommer 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 identique au verbe "tests".
Il n’ya pas de limite à votre créativité pour nommer les tests, de sorte que nous obtenions des en-têtes de phrase complets pour eux.
Habituellement, les noms de test devront commencer par un verbe.
Les exemples comprennent:
etc.
Une autre option consiste à utiliser "cela" au lieu de "si".
Ce dernier me permet d’éviter les frappes au clavier et décrit plus précisément ce que je fais, car je ne sais pas, que le testé le comportement est présent, mais je teste si c'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 Si peut être déroutant lorsqu’on travaille avec des interfaces. Il se trouve que la classe de test IfSerializer.cs est très similaire à l'interface ISerializer.cs dans l'onglet "Ouvrir les fichiers". Cela peut être très gênant lors du basculement entre les tests, la classe testée et son interface. En conséquence, je choisirais maintenant cela plus If comme préfixe.
De plus, j'utilise maintenant - uniquement pour les méthodes de mes classes de test car ce n'est pas considéré comme la meilleure pratique nulle part ailleurs - le "_" pour séparer les mots dans les noms de mes méthodes de test comme suit:
Je trouve cela plus facile à lire.
[ Fin éditer ]
J'espère que cela suscitera d'autres idées, car je considère l'attribution de nom aux tests d'une grande importance car cela peut vous faire gagner beaucoup de temps qui aurait autrement été passé à essayer de comprendre ce que font les tests (par exemple, après la reprise d'un projet après une interruption prolongée) .
Je pense que l’un des aspects les plus importants est d’être cohérent dans votre convention de dénomination (et de l’accord avec les autres membres de votre équipe). Trop souvent, je vois des tonnes de conventions différentes utilisées dans le même projet.
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 de fixture de test unitaire et les nomme d'après le type de fonctionnalité que je teste. Les méthodes [Test] sont nommées comme suit: 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
Je devrais 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 fardeau du code une fois prêt à le déployer sans avoir à effectuer un grand nombre de modèles d’exclusion.
Personnellement, j’aime bien les meilleures pratiques décrites dans "JUnit Pocket Guide" ... c’est difficile de battre un livre écrit par le co-auteur de JUnit!
le nom du scénario de test de la classe Foo doit être FooTestCase ou quelque chose de similaire (FooIntegrationTestCase ou FooAcceptanceTestCase) - puisqu'il s'agit d'un scénario de test. voir http://xunitpatterns.com/ pour connaître certaines conventions de dénomination standard telles que test, scénario de test, dispositif de test, méthode de test, etc.