web-dev-qa-db-fra.com

Un test unitaire est-il considéré comme fragile s'il échoue lorsque la logique métier change?

Veuillez consulter le code ci-dessous; il vérifie si une personne de sexe féminin est admissible à l'offre1:

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id,"Offer1");
    Assert.False(offer1.IsEligible(person));
}

Ce test unitaire réussit. Cependant, il échouera si "Offer1" est proposé aux femmes à l'avenir.

Est-il acceptable de dire - si la logique métier entourant l'offre 1 change, le test unitaire doit changer. Veuillez noter que dans certains cas (pour certaines offres) la logique métier est modifiée dans la base de données comme ceci:

update Offers set Gender='M' where offer=1;

et dans certains cas dans le modèle de domaine comme celui-ci:

if (Gender=Gender.Male)
{
  //do something
}

Veuillez également noter que dans certains cas, la logique de domaine derrière propose des changements régulièrement et dans certains cas, ce n'est pas le cas.

27
w0051977

Ce n'est pas fragile au sens habituel. Un test unitaire est considéré comme fragile s'il se casse en raison de changements d'implémentation qui n'affectent pas le comportement sous test. Mais si la logique métier elle-même change, alors un test de cette logique est supposé à casser.

Cela dit, si la logique métier change en effet souvent, il n'est peut-être pas approprié de coder en dur les attentes dans les tests unitaires. Au lieu de cela, vous pouvez tester si les configurations de la base de données affectent les offres comme prévu.

Le nom du test Returns False When Given A Person With A Gender Of Female ne décrit pas de règle métier. Une règle commerciale serait quelque chose comme Offers Applicable to M should not be applied to persons of gender F.

Vous pouvez donc écrire un test qui confirme que si une offre est définie comme applicable uniquement aux personnes de type M, alors une personne de type F ne sera pas indiquée comme éligible. Ce test garantira que la logique fonctionne même si la configuration des offres spécifiques change.

77
JacquesB

Lorsque la propriété est définie dans la base de données de production (ou un clone pour les tests), ce n'est pas un test unitaire . Un test unitaire vérifie une unité de travail et ne nécessite pas un état externe particulier pour fonctionner. Cela suppose que Offer1 Est défini dans la base de données comme une offre réservée aux hommes. C'est un état extérieur. Il s'agit donc davantage d'un test d'intégration , en particulier d'un système ou acceptation test. Notez que les tests d'acceptation ne sont souvent pas scriptés (pas exécutés dans un cadre de test mais exécutés manuellement par des êtres humains).

Lorsque la propriété est définie dans le modèle de domaine avec une instruction if, le même test est un test unitaire. Et cela peut être fragile. Mais le vrai problème est que le code est fragile. En règle générale, votre code sera plus résistant si le comportement de l'entreprise est configurable plutôt que codé en dur. Parce qu'un déploiement Rush pour corriger une petite erreur de codage devrait être rare. Mais une exigence commerciale qui change sans préavis n'est qu'un mardi (quelque chose qui se produit chaque semaine).

Vous utilisez peut-être un framework de test unitaire pour exécuter le test. Mais les frameworks de tests unitaires ne se limitent pas à l'exécution de tests unitaires. Ils peuvent également exécuter des tests d'intégration.

Si vous écriviez un test unitaire, vous créeriez à la fois person et offer1 Sans se fier à l'état de la base de données. Quelque chose comme

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
    offer1.markLimitedToGender("M");

    Assert.False(offer1.IsEligible(person));
}

Notez que cela ne change pas en fonction de la logique métier. Cela n'affirme pas que offer1 Rejette les femmes. Cela fait de offer1 Le type d'offre qui rejette les femmes.

Vous pouvez créer et configurer la base de données dans le cadre du test. En C #, en utilisant NUnit, ou dans JUnit de Java, vous configureriez la base de données dans une méthode Setup. Vraisemblablement, votre framework de test a une notion similaire. Dans cette méthode, vous pouvez insérer des enregistrements dans la base de données avec SQL.

S'il vous est difficile d'écrire du code qui substitue une base de données de test à la base de données de production, cela ressemble à une faiblesse de test dans votre application. Pour les tests, il serait préférable d'utiliser quelque chose comme l'injection de dépendance qui permet la substitution. Ensuite, vous pouvez écrire des tests indépendants des règles métier actuelles.

Un avantage secondaire de cela est qu'il est souvent plus facile pour le propriétaire de l'entreprise (pas nécessairement le propriétaire de l'entreprise, plus comme la personne responsable de ce produit dans la hiérarchie de l'entreprise) de configurer directement les règles métier. Parce que si vous disposez de ce type de cadre technique, il est facile d'autoriser le propriétaire de l'entreprise à utiliser une interface utilisateur (UI) pour configurer l'offre. Le propriétaire de l'entreprise sélectionnerait la limitation dans l'interface utilisateur et émettrait l'appel markLimitedToGender("M"). Ensuite, lorsque l'offre est conservée dans la base de données, elle est stockée. Mais vous n'auriez pas besoin de stocker l'offre pour l'utiliser. Vos tests pourraient donc créer et configurer une offre qui n'existe pas dans la base de données.

Dans votre système tel que décrit, le propriétaire de l'entreprise devra soumettre une demande au groupe technique, qui émettra le code SQL approprié et mettra à jour les tests. Ou le groupe technique doit éditer votre code et vos tests (ou tests puis coder). Cela semble une approche plutôt lourde. Tu peux le faire. Mais votre logiciel (pas seulement vos tests) serait moins fragile si vous n'aviez pas à le faire.

TL; DR : vous pouvez écrire des tests comme celui-ci, mais il vaut peut-être mieux écrire votre logiciel pour ne pas avoir à le faire.

14
mdfst13