est-il préférable d'ajouter des fonctions qui renvoient l'état interne d'un objet pour des tests unitaires, par opposition à la fabrication de la classe de test un ami? - surtout, quand il n'y a aucune utilité pour les fonctions, à l'exception du cas d'essais de l'unité. P>
6 Réponses :
Je recommande d'utiliser des accesseurs plutôt que de permettre l'accès via des membres publics ou des classes d'amis. p>
Je ne pense pas que l'utilisation de la classe d'amis vous procure des avantages, et cela a le potentiel de rendre votre vie beaucoup plus malade de la route. Si votre code va rester pendant une longue période, il y a de bonnes chances que cela puisse être utilisé de manière à ne pas anticiper. Les fonctions d'accès ne peuvent être utilisées que pour les tests maintenant, mais qui sait ce qui se passera dans le futur? L'utilisation d'accesseurs plutôt que de fournir un accès direct aux variables vous donne beaucoup plus de flexibilité, et il a un coût très faible. p>
L'autre argument est que l'utilisation des accesseurs plutôt que des membres du public est une bonne habitude. Développer de bonnes habitudes est une compétence importante en tant que programmeur. p>
Pour vous assurer de vous comprendre, un accesseur pour la double fois variable; Je crée créerait: double temps () const;
Oui, pour deux raisons: 1, il indique à d'autres programmeurs ce que vous voulez qu'ils puissent faire avec les données, et 2: le compilateur peut souvent optimiser les fonctions de constence qu'il ne pouvait pas sans l'identifiant Const.
Oh, oui, notez que le temps variable et une fonction de fonction () ne compileront pas; La plupart des gens ont la variable réelle avec un soulignement de fuite comme Time_, et l'accessoir comme Time () {Return Time_; }
Les tests unitaires devraient que 95% du temps ne teste que la surface exposée publiquement d'une classe. Si vous testez quelque chose sous les couvertures, cela teste les détails de la mise en œuvre, qui est intrinsèquement fragile, car vous devriez pouvoir modifier facilement la mise en œuvre et que les tests fonctionnent toujours. Non seulement c'est fragile, mais vous pourriez également être tenté de tester des choses qui ne sont pas réellement possibles dans des scénarios d'utilisation planifiés, ce qui est une perte de temps. P>
Si le point des accesseurs que vous souhaitez ajouter est simplement de tester si la fonction avait l'effet souhaité, votre conception de classe peut violer un autre principe, ce qui est qu'une classe semblable à une machine à l'état devrait toujours préciser quel état C'est dans, si cela affecte ce qui se passe lorsque les gens interagissent avec la classe. Dans ce cas, il serait vrai de fournir ces accesseurs en lecture seule. Si cela n'affecte pas le comportement de la classe, reportez-vous à mon précédent bit sur les détails de la mise en œuvre. P>
Et comme vous l'avez dit à juste titre, encombrer la surface publique d'une classe avec des trucs inutilisés est également indésirable pour ses propres raisons. p>
Si je avait em> pour choisir entre les accesseurs et les amis dans votre cas, je choisirais d'être ami, simplement parce que vous em> possède votre test et peut le changer dans une pincée. Vous ne pouvez peut-être pas posséder le code par le clown qui trouve un moyen d'utiliser vos accesseurs supplémentaires, puis vous serez coincé. P>
Je suis en désaccord avec la réponse acceptée et recommanderai plutôt l'utilisation d'une classe d'amis. p>
Une partie de l'état que vous testez est probablement spécifique à la mise en œuvre de votre classe; Vous testez des détails que le autre code ne connaît normalement pas et ne se souciait pas et ne devrait pas compter sur. Les fonctions d'accessoires publics rendent ces détails de la mise en œuvre une partie de l'interface de la classe. Si l'état interne que vous testez ne fait pas partie de l'interface envisagée, il ne devrait pas être visible par des fonctions publiques. D'un point de vue puriste, vous êtes coincé entre deux mauvaises réponses, car les classes d'amis sont également techniquement faisant partie de l'interface publique. Dans mon esprit, la question devient, quelle option est moins susceptible de conduire à de mauvais choix de codage sur la route? Vous accédez à un ensemble de fonctions d'accessoires publics dépendantes de la mise en œuvre encourageront par inadvertance un modèle conceptuel dépendant de la mise en œuvre de la classe, conduisant à une utilisation de la classe dépendante de la mise en œuvre. Une classe d'une seule ami, nommée de manière appropriée et documentée, est moins susceptible d'être maltraitée. P>
Bien que, en général, je suis tout à fait d'accord avec la recommandation de préférer les fonctions d'accesseur par rapport à l'accès direct aux variables des membres, je ne suis pas d'accord sur le fait que cette meilleure pratique s'applique au test d'unités de l'état interne dépendant de la mise en œuvre. Un terrain moyen raisonnable est d'utiliser les fonctions d'accessoir privé em> à ces éléments d'état que votre test de l'unité se souciera et sera suffisamment disciplinée pour utiliser les fonctions d'accesseur dans vos tests unitaires. Juste mon avis. P>
Que diriez-vous de faire de l'état interne "protégé"? Et ensuite faire unitest utilisant une classe dérivée. P>
protégé a une pire protection d'encapsulation que d'un ami. Toute personne B> Héritage de votre classe aurait un accès légitime. Et parce que vous les avez mis protégé, vous dites que cela est en effet soutenu. Au moins, une classe d'amis avec un nom spécifique Classe d'amis MyObjectOnlyforestingPurée de vue code> limitera l'accès à une classe avec un nom spécifique. . . Dans l'ensemble, c'est comme donner les clés de votre appartement à un ami, contre les clés à tous ceux de votre famille (y compris le demi-frère du mari de votre fille)
Je pense qu'il doit exister une distinction entre la vérification future de la classe en fournissant des accesseurs à ses utilisateurs s'il est logique de le faire et d'améliorer la qualification. Je ne suis pas non plus un grand fan de classes d'amitié pour le seul but de tester car cela introduit un couplage serré dans un endroit où je préfère ne pas l'avoir. P>
Si l'utilisation exclusive des accesseurs est de fournir un moyen pour les cas de test de vérifier l'état interne de la classe, il n'a généralement aucun sens de les exposer publiquement. Il peut également attacher les détails de la mise en œuvre que vous voudrez peut-être changer plus tard, mais que vous ne trouvez pas que vous ne pouvez pas parce que quelqu'un d'autre utilise lesdits accesseurs. P>
Ma solution préférée pour cela serait de fournir des fonctions EM> protégées EM> pour communiquer clairement aux utilisateurs de la classe qui ne font pas partie de l'interface publique. Vos tests créeraient ensuite une classe dérivée minimale de l'original qui contient des talons d'appel pour les fonctions du parent, mais rend également les accessoires publics afin de pouvoir les utiliser dans les cas de test. P>
Les classes de la classe ne feraient pas la considération des clients / utilisateurs de la classe, autant que les clients / utilisateurs de l'interface publique sont? Sauf si la seule classe dérivée est le talon de test de l'unité, vous avez le même problème que si vous aviez effectué les accesseurs public - les écrivains de classes dérivés ne peuvent pas indiquer quelles fonctions protégées sont correctes à appeler et qui ne devraient être utilisées que pour les tests. fins. Si vous modifiez les fonctions liées aux tests, vous risquez de casser des classes dérivées qui ne savaient pas de ne pas utiliser un accesseur.
Utiliser des classes d'amis pour le test de l'unité est parfaitement légitime et vous permet de maintenir l'encapsulation. Vous ne devez pas modifier votre interface publique de classe simplement pour rendre la classe plus testable. Pensez-y de cette façon. Et si vous avez acheté une bibliothèque FTP tiers et que vous essayez de l'utiliser et que l'interface publique est encombrée d'un tas de méthodes que vous n'avez même pas besoin de savoir simplement à cause des tests unitaires! Même la modification d'une interface protégée pour compenser les tests d'unités est mauvaise. Si je hérite d'une certaine classe, je ne veux pas avoir à vous soucier de quelles méthodes sont utiles pour moi et lesquelles sont seulement là à cause des tests d'unité !!! L'utilisation de classes d'amis pour des tests d'unité vous aide à conserver une interface de classe simple, plus facile à utiliser; Il aide à préserver l'encapsulation et l'abstraction !!! p>
J'ai entendu l'argument selon lequel l'utilisation de classes d'amis pour des tests d'unités est mauvaise car la classe sous test ne doit pas être "étroitement couplée" avec sa classe de test et ne devrait pas "savoir" quelque chose sur sa classe de test. Je n'ai pas acheté ça. C'est une seule ligne ajoutée au sommet de la classe: p>
Classe d'amis MyClasStest; p>
Et maintenant, vous pouvez tester votre classe de votre choix! p>
Maintenant, je suis d'accord pour que vous ne devriez pas utiliser une classe d'amis, à moins que cela ne soit nécessaire. Si vous pouvez tester ce qui nécessite des tests sans faire un ami, par tous les moyens. Mais si la vie devient difficile et que l'utilisation d'une classe d'amis facilite la vie, utilisez-le! P>
Duplicaté possible de Comment Dois-je tester une classe qui a des méthodes privées, des champs ou des classes intérieures?