Affirmer des messages dans les tests

Rebonjour. En prévision du début du cours «Développeur C #», nous avons traduit du matériel intéressant sur les messages d'affirmation dans les tests et sommes heureux de partager la traduction avec vous.




Dans cet article, nous verrons si vous devez utiliser les messages Assert dans vos tests.

J'ai reçu une question intéressante d'un collègue lecteur, sur laquelle j'aimerais m'attarder plus en détail:

J'ai une question sur les messages Assert: dois-je utiliser la surcharge contenant le paramètre message et l'utiliser pour envoyer une chaîne décrivant la raison de l'échec d'Assert (également «Revendications») ?

La réponse à cette question se résume à deux aspects:

  • Lisibilité du test - à quel point il est facile de comprendre ce que fait le test.
  • Facilité de diagnostic - à quel point il est facile de comprendre pourquoi le test échoue.

Discutons chacun d'eux individuellement

Test de lisibilité


Les gens utilisent souvent les messages Assert pour aider les membres de l'équipe et eux-mêmes à l'avenir à comprendre ce qui se passe dans le test. Regardons l'exemple suivant:

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    Assert.AreEqual(UserType.Employee, person.Type); //  
    Assert.AreEqual(1, company.NumberOfEmployees); //  
}

Au lieu d'une assertion nue, vous pouvez également indiquer la raison pour laquelle l'assertion de test valide quelque chose:

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    Assert.AreEqual(UserType.Employee, person.Type, "Person must become an employee after hiring");
    Assert.AreEqual(1, company.NumberOfEmployees, "Number of employees must increase");
}

De telles déclarations aident, mais elles ont un prix. Ces messages vous demandent

  • Passez du temps à les écrire
  • Continuez à les faire avancer

Ici, l'ensemble des avantages et des inconvénients est le même que dans les commentaires sur le code. Et, comme dans le cas des commentaires, je vous conseille: n'écrivez pas de messages d'affirmation uniquement à des fins de lisibilité. Si vous pensez que le test n'est pas évident sans messages d'affirmation, essayez plutôt de le refactoriser. À long terme, il est plus facile de faire parler le test de lui-même que de le synchroniser avec les messages d’affirmation (et ce n’est qu’une question de temps avant que la synchronisation ne soit interrompue).

Entrez des messages d'affirmation uniquement lorsque cela est absolument nécessaire - lorsque vous ne pouvez pas améliorer la lisibilité du test d'une autre manière. Mais même alors, inclinez-vous à choisir de ne pas les écrire.

Le moyen le plus simple d'obtenir un gain rapide de lisibilité du test est de passer à un enregistrement d'instructions lisible. Par exemple, NUnit dispose d'un modèle d'instruction basé sur des contraintes spéciales qui vous aide à écrire vos instructions de la manière suivante:

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    Assert.That(person.Type, Is.EqualTo(UserType.Employee));
    Assert.That(company.NumberOfEmployees, Is.EqualTo(1));
}

Ou vous pouvez utiliser mes assertions Fluent préférées :

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    person.Type.Should().Be(UserType.Employee);
    company.NumberOfEmployees.Should().Be(1);
}

Ces instructions sont lues dans un anglais simple - exactement de la manière dont vous souhaitez que tout votre code soit lu. Nous, les humains, préférons percevoir les informations sous forme d'histoires. Toutes les histoires adhèrent à ce modèle:

[] [] [].

Par exemple,

  .

Ici - le sujet, - l'action et - l'objet. Il en va de même pour le code.

Cette version

company.NumberOfEmployees.Should().Be(1);

lit mieux que

Assert.AreEqual(1, company.NumberOfEmployees);

précisément parce que l'histoire est retracée ici.
, . , .


Une autre vue des messages d'affirmation est en termes de facilité de diagnostic. En d'autres termes, la simplicité de comprendre la cause d'un échec de test sans examiner le code de ce test. Ceci est utile lors de la lecture des résultats d'un assemblage CI.

D'un point de vue diagnostic, suivez ce guide: si vous pouvez facilement redémarrer le test localement, ce test n'a pas besoin d'un message d'assertion. Cela est vrai pour tous les tests unitaires (car ils ne fonctionnent pas avec des dépendances hors processus), mais dans une moindre mesure pour les tests d'intégration et de bout en bout.


Test de la pyramide

Lorsque vous montez plus haut dans la pyramide des tests, vous aurez peut-être besoin d'informations plus détaillées, car les tests d'intégration (et en particulier de bout en bout) sont plus lents et vous ne pourrez peut-être pas les réexécuter à volonté.

Mais même avec des tests d'intégration et de bout en bout, il existe des moyens de faciliter les diagnostics sans recourir à des messages de confirmation:

  • Faites du test test un module de comportement - lorsqu'un test vérifie une chose, il est souvent facile de déterminer ce qui a mal tourné. (Cela ne s'applique pas toujours aux tests de bout en bout, car vous souhaiterez peut-être que ces tests vérifient comment plusieurs unités de comportement fonctionnent étroitement).
  • Nommez vos tests unitaires en conséquence - Le nom de test idéal décrit le comportement de l'application en termes commerciaux afin que même un non-programmeur puisse le comprendre.

Et n'oubliez pas que même sans instructions utilisateur, vous avez toujours les messages que l'environnement de test unitaire génère pour vous.

Par exemple, une erreur dans l'instruction suivante:

person.Type.Should().Be(UserType.Employee);

donne le message d'erreur suivant:

Xunit.Sdk.EqualException: Assert.Equal() Failure
Expected: Employee
Actual:   Customer

La combinaison de ces messages générés par l'environnement et des noms de test lisibles par l'homme rend inutile 90% des messages affirmés par l'utilisateur, même en termes de facilité de diagnostic. La seule exception est les longs tests de bout en bout. Ils contiennent souvent des vérifications en plusieurs étapes, il est donc judicieux d'utiliser des messages d'assertion supplémentaires pour comprendre laquelle des étapes a échoué. Cependant, il ne devrait pas y avoir beaucoup de ces tests de bout en bout.

Bien sûr, afin de tirer parti des messages d'erreur générés par le framework, vous devez éviter les comparaisons booléennes courantes, telles que:

(person.Type == UserType.Employee).Should().BeTrue();

Parce qu'ils conduisent au message d'erreur suivant:

Xunit.Sdk.TrueException: Assert.True() Failure
Expected: True
Actual:   False

Ce qui n'aide pas du tout au diagnostic.

Sommaire


Vous sentez-vous souvent paresseux lorsqu'il s'agit de rédiger des déclarations? Eh bien, maintenant vous pouvez le justifier et envoyer vos collègues à cet article.


"Je suis content que cela ait un nom"

Blagues à part, cependant, voici un résumé:

  • L'utilisation des messages d'assertion comporte deux aspects:
    • Lisibilité du test (à quel point il est facile de comprendre ce que fait le test).
    • Facilité de diagnostic (à quel point il est facile de comprendre pourquoi le test échoue lors de la construction de CI).
  • En termes de lisibilité des tests, les messages d'affirmation sont des commentaires de code. Au lieu de vous y fier, refactorisez votre test pour atteindre la lisibilité.
  • En termes de facilité de diagnostic, la meilleure alternative pour affirmer des messages est:
    • Test d'un module de comportement unique par un test
    • Tests de dénomination en termes commerciaux
  • La seule exception est les longs tests de bout en bout.

C'est tout. Vous pouvez en savoir plus sur notre cours lors du webinaire gratuit , qui se tiendra aujourd'hui.

All Articles