16

[Bien sûr, la question ne se limite pas à une mise en œuvre « ami » spécifique, ne hésitez pas que souligner des détails de mise en œuvre le cas échéant]Utiliser les déclarations "friend" pour les tests unitaires. Mauvaise idée?

En lisant les questions sans réponse, je suis tombé sur l'attribut InternalsVisibleTo:

Spécifie que les types qui sont ordinairement visible que dans le ensemble courant sont visibles à un autre ensemble.

Le C# Programming Guide sur MSDN a une section Friend Assemblies décrivant comment utiliser l'attribut pour permettre l'utilisation des méthodes et types internal à un autre ensemble. Je me demande si ce serait une bonne idée d'utiliser ceci pour créer une interface "cachée" pour instrumentation d'une bibliothèque à utiliser par l'ensemble de test unitaire. Il semble augmenter massivement le couplage dans les deux sens (code de test dans l'assemblage de production, connaissance interne intime de l'assemblage de production dans le code de test), mais d'un autre côté, il peut aider à créer des tests fins sans encombrer l'interface publique.

Quelle est votre expérience d'utilisation des déclarations d'amis lors des tests? Était-ce votre Silver Bullet, ou a-t-elle commencé la Death March?

Répondre

13

J'ai largement utilisé cette technique - cela signifie que mes tests unitaires peuvent tester des aspects de la bibliothèque de codes qui ne sont pas visibles par les consommateurs normaux.

Alors que l'utilisation [InternalsVisibleTo] augmente le couplage, je crois que l'augmentation (mineure) vaut bien les gains. Mes tests unitaires sont déjà étroitement couplés au code testé - bien que j'essaie d'écrire des tests qui garantissent des résultats spécifiques, pas des implémentations spécifiques, en accédant à des choses non visibles par les consommateurs habituels, je contraint quelque peu l'implémentation.

En sens inverse, le couplage est minime - en ayant l'attribut [InternalsVisibleTo] sur l'ensemble de code, et pour marquer certaines choses comme interne au lieu de privé (ou protégés au lieu de interne protégé) .

(Notez que je suis ignorant ici des changements de conception qui sont provoqués par l'utilisation de tests unitaires, ce qui est un tout autre débat.)

L'attribut [InternalsVisibleTo] nécessite une forte nommer vos assemblées. Si vous ne le faites pas déjà, vous pouvez trouver cela un peu lourd car un assembly fortement nommé peut seulement dépendre d'autres assemblys fortement nommés, ce qui peut vous amener à devoir modifier plusieurs assemblys.

Obtenir l'attribut correct peut être un peu fastidieux, car il doit inclure la clé publique de votre ensemble de test. IDesign a un Friend Assembly tool utile qui crée l'attribut dans votre presse-papiers, prêt à être collé. Conseillé.

+0

Merci pour le conseil sur la dénomination forte! Je n'étais pas (encore) conscient de cela, mais comme je pense que toutes mes assemblées doivent être fortement nommées pour être publiées, je ne vois pas cela comme un vrai problème. –

12

C'est la seule utilisation que j'ai jamais personnellement appliquée à InternalsVisibleTo - et c'était très, très pratique en effet.

Je ne considère pas les tests unitaires comme des tests de boîte noire - ils sont déjà couplés à l'implémentation dans une certaine mesure. Etre capable de tester les types et les méthodes internes permet un focus beaucoup plus serré (unités plus petites).

3

Je pense que l'utilisation de InternalsVisibleToAttribute pour permettre le test unitaire est parfaitement raisonnable. Mon "unité" dans "unité de test" est une classe, et cela inclut internal classes, donc je veux les tester. I don't want to unit test private methods, cependant.

Je ne pense pas que la création d'une interface privée spéciale juste pour les tests est une bonne idée. L'une des valeurs des tests unitaires est que cela vous donne une chance de penser à l'interface de votre classe du point de vue d'un consommateur de cette classe; Fournir une porte arrière prend cet avantage.

Ma préférence, cependant, est de mettre mes tests unitaires dans le même assemblage que mon code de production. Cela n'affecte généralement pas mon client, mais cela simplifie les choses pour moi, alors je le fais. Quand je le fais, cela fait disparaître la question InternalsVisibleTo.

3

En fait, le test unitaire est le seulement que j'ai pu utiliser pour utiliser le InternalsVisibleToAttribute pour. Avec cela, vous pouvez implémenter une grande partie de vos méthodes «privées» comme internes au lieu de les exposer à la structure de test unitaire pour des tests plus invasifs des invariants internes à la classe.

J'ai eu beaucoup de succès avec cette technique. Si rien d'autre ne vous aide à atteindre cet objectif mythique de couverture de code à 100% en vous permettant d'invoquer des méthodes privées dans des situations qui sont autrement inaccessibles.

2

Je pense qu'un autre cas d'utilisation légitime intervient lorsque vous avez utilisé des assemblages séparés lors de la fusion de code C++ hérité avec du code C# plus récent.

Nous avons pris les assemblys C++, les avons convertis en C++/CLI, puis implémentons du code plus récent en C#. Lorsque nous faisons cela, nous utilisons toujours "internal" pour les classes/méthodes en C# qui ne sont pas vraiment publiques, et les rendons disponibles au code hérité en tant qu'assemblées d'amis.

Questions connexes