web-dev-qa-db-fra.com

Est-il important de tester un constructeur unitaire?

Dois-je tester les constructeurs unitaires? Disons que j'ai un constructeur comme celui-ci:

IMapinfoWrapper wrapper;
public SystemInfo(IMapinfoWrapper mapinfoWrapper)
{
    this.wrapper = mapinfoWrapper;
}

Dois-je faire un test unitaire pour ce constructeur? Je n'ai pas de getters pour la variable wrapper, donc je n'ai pas besoin de tester cela.

71
Nathan W

Le test unitaire consiste à tester les états publics, les comportements et les interactions de vos objets.

Si vous définissez simplement un champ privé dans votre constructeur, qu'y a-t-il à tester?

Ne vous embêtez pas à tester unitairement vos simples accesseurs et mutateurs. C'est tout simplement stupide et cela n'aide personne.

93
yfeldblum

Oui. Si vous avez une logique dans votre constructeur, vous devez la tester. Le simple fait de définir des propriétés n'est pas une logique OMI. Conditions, flux de contrôle, etc. IS logic.

Edit: Vous devriez probablement tester quand IMapinfoWrapper est nul, si cette dépendance est requise. Si c'est le cas, alors c'est logique et vous devriez avoir un test qui intercepte votre ArgumentNullException ou quoi que ce soit ... vos tests sont des spécifications qui définissent comment le code se comporte. S'il déclenche une ArgumentNullException, cela doit être spécifié dans un test.

35
Brian Genisio

Q: Si vous définissez une variable membre dans le constructeur, pourquoi la définissez-vous?.

R: Parce que vous avez un test unitaire qui échoue et qui ne peut être réussi que si vous le définissez dans le constructeur.

Si vous utilisez cette logique, où vous écrivez uniquement du code pour faire passer un test unitaire (Test Driven Development), alors vous aurez déjà la réponse à votre question.

13
John Sonmez

Non. Sa fonctionnalité sera testée par tous les autres tests unitaires de la classe.

8
Draemon

Vous devez absolument tester le constructeur. Si vous avez un constructeur par défaut, vous devez tester qu'il peut être appelé. Que se passe-t-il si plus tard la classe est modifiée - peut-être qu'elle devient un singleton ou que le constructeur par défaut est supprimé au profit de celui qui nécessite des paramètres? Dans ce cas, le test doit échouer pour alerter ce changement (afin que la classe ou le test puisse être fixé pour répondre à la nouvelle exigence).

La présence d'un constructeur par défaut est une exigence qui devrait avoir un test. Même si le constructeur ne fait que définir des membres privés qui seront testés ailleurs, le fait qu'il existe un constructeur sans paramètre doit être testé.

6
c g

Je teste des constructeurs lorsqu'ils contiennent de la logique - par exemple validation ou paramétrage conditionnel d'un état privé. Les erreurs de validation se terminent par une exception levée par le constructeur. Une exécution réussie se termine par une création d'objet qui présente un comportement spécifique en fonction de l'état défini dans le constructeur. Dans les deux cas, cela nécessite des tests. Mais les tests de constructeur sont ennuyeux car ils se ressemblent tous - invoquez le constructeur, faites une assertion. Les déclarations de méthode de test prennent souvent plus de place que toute la logique de test ... J'ai donc écrit une bibliothèque de test simple qui aide à écrire des tests déclaratifs pour les constructeurs: Comment tester facilement la logique de validation dans les constructeurs en C #

Voici un exemple dans lequel j'essaie sept cas de test sur un constructeur d'une classe:

[TestMethod]
public void Constructor_FullTest()
{

    IDrawingContext context = new Mock<IDrawingContext>().Object; 

    ConstructorTests<Frame>
        .For(typeof(int), typeof(int), typeof(IDrawingContext))
        .Fail(new object[] { -3, 5, context }, typeof(ArgumentException), "Negative  length")
        .Fail(new object[] { 0, 5, context }, typeof(ArgumentException), "Zero length")
        .Fail(new object[] { 5, -3, context }, typeof(ArgumentException), "Negative width")
        .Fail(new object[] { 5, 0, context }, typeof(ArgumentException), "Zero width")
        .Fail(new object[] { 5, 5, null }, typeof(ArgumentNullException), "Null drawing context")
        .Succeed(new object[] { 1, 1, context }, "Small positive length and width")
        .Succeed(new object[] { 3, 4, context }, "Larger positive length and width")
        .Assert();

}

De cette façon, je peux tester tous les cas pertinents pour mon constructeur sans taper beaucoup.

4
Zoran Horvat

Dans de nombreux environnements réglementés par la FDA, un code plus critique doit être testé à 100% ... y compris la construction de classes. Ainsi, le test des constructeurs est parfois nécessaire quel que soit le raisonnement pour ou non les tester. De plus, les entreprises qui utilisent des outils d'analyse statique devront s'assurer que TOUS les membres de données d'une classe sont correctement initialisés afin de ne pas avoir d'erreurs bien que le code puisse s'exécuter sans heurts et sans erreurs. Habituellement, l'initialisation des membres de données se fait dans le constructeur ... juste matière à réflexion.

3
Brandon

Ça dépend.

Je ne prendrais pas la peine d'écrire un test de constructeur dédié pour quelque chose d'aussi simple que l'exemple que vous avez donné.

Cependant, si vous avez des tests logiques dans le constructeur tels qu'une validation de paramètre, alors oui, absolument. Bien que, comme l'affiche originale, je ne travaille pas dans le constructeur si possible, il est courant que la validation des paramètres soit effectuée. Dans ce cas, il est inévitable d'empêcher le constructeur de faire certains travail. S'il y a de la logique dans le constructeur, il y a toujours la possibilité que ce soit faux, donc je le traite comme n'importe quel autre appel de méthode et le teste de manière appropriée.

3
Mark Simpson

Je pense que la réponse à cette question est "Oui".

Il y a beaucoup de code qui suppose, horriblement, un état d'objet initialisé, au lieu d'une référence nulle - souvent quand aucune valeur explicite n'est affectée dans le constructeur.

Je suis heureux que les tests des constructeurs soient interrompus pour m'alerter lorsque les valeurs de membre public initialisées ont été modifiées. Il s'agit de tests défensifs - je suis pragmatique et plus heureux d'avoir des tests que de ne pas le faire, et de les supprimer lorsqu'ils s'avèrent ne pas être utiles ou utiles.

1
badcop666

Je crois en une couverture à 100%. Également une couverture à 100% non pas simplement en testant des interactions simples en se moquant des choses ou simplement en définissant et en obtenant des choses, mais plus de tests d'intégration/d'acceptation qui vérifient la fonctionnalité. Donc, si vous finissez par écrire de très bons tests d'intégration/d'acceptation, tous vos constructeurs (et les méthodes simples telles que les setters et les getters) doivent être appelés.

1
digiarnie

Le test des accesseurs et des mutateurs est également nécessaire à moins que le développeur ne s'assure qu'aucune logique d'état ne peut être modifiée. Par exemple, si l'on utilise le modèle de conception pour un Singleton, souvent des accesseurs ou des propriétés sont utilisés, et si la classe n'est pas initialisée, cela se fait à partir de l'accesseur puisque le constructeur est privé. En C++, on peut rendre leurs fonctions const ou statiques dans lesquelles les membres de données de la classe ne peuvent pas être modifiés. (Remarque: même l'utilisation de l'électricité statique est un peu risquée, car ces variables sont souvent globales.) Cependant, sans test, si quelqu'un ne parvient pas à utiliser des mesures préventives, comment pouvez-vous garantir avec une précision de 100% que ce qui est écrit ne peut pas devenir un échec temps? L'entretien n'est pas infaillible.

1
Brandon

Quel comportement d'une instance de SystemInfo dépend de la valeur de wrapper?

Si quelque chose peut mal tourner (par exemple, une valeur nulle provoque une rupture), je suggère d'écrire des scénarios décrivant chacune de ces situations et de les utiliser pour piloter la définition des tests unitaires appropriés.

Si tous les scénarios finissent par dépendre de l'état ou du comportement de l'instance privée de IMapinfoWrapper, je suggère plutôt d'écrire des tests unitaires sur cette classe.

0
joel.neely

Si le constructeur contient une logique, telle que l'initialisation d'une classe, je pense que vous devriez tester le constructeur même. Ou vous pouvez parler au développeur que le fait de mettre l'initialisation dans le constructeur réduira la testabilité du code testé.

0
Magus

Sauf si vous écrivez un compilateur, car vous ne feriez que tester que le compilateur pourrait générer du code pour effectuer des affectations, ce qui est normalement inutile.

Maintenant, dans une situation plus habituelle, si vous voulez faire autre chose avec le wrapper, il y a peut-être un point. Par exemple, vous pouvez lever une ArgumentNullException si vous essayez de passer un null, et en théorie, cela pourrait avoir un test unitaire. Même alors, la valeur du test est assez minime.

Personnellement, je ne teste presque jamais explicitement les constructeurs. S'ils sont suffisamment compliqués pour nécessiter des tests, j'ai tendance à penser que le code est un peu malodorant.

0
Jim Cooper