Je suis tout à fait un débutant dans les tests de code, et j'étais une assert
putain avant. Une chose qui m'inquiète dans les tests unitaires est que cela vous oblige souvent à faire public
(ou au moins internal
) des champs qui auraient été private
autrement, à les défaire readonly
, à faire des private
méthodes à la protected virtual
place, etc ...
J'ai récemment découvert que vous pouvez éviter cela en utilisant des choses comme la classe PrivateObject pour accéder à n'importe quoi dans un objet via la réflexion. Mais cela rend vos tests moins maintenables (les choses échoueront à l'exécution plutôt qu'à la compilation, elles seront cassées par un simple renommage, c'est plus difficile à déboguer ...). Quelle est votre opinion à ce sujet ? Quelles sont les meilleures pratiques en matière de tests unitaires concernant la restriction d'accès?
edit: considérez par exemple que vous avez une classe avec un cache dans un fichier sur le disque, et dans vos tests vous voulez écrire en mémoire à la place.
la source
Réponses:
Vous ne devriez jamais avoir à
En particulier, la non-ré-liaison d'un champ peut rendre un objet immuable mutable, et ce serait un désastre.
Vos tests doivent considérer vos objets comme des boîtes noires ( Wikipedia ), ce qui signifie qu'ils ne doivent s'intéresser qu'à l'interface publique des objets, pas aux détails de leur implémentation.
Si un objet ne peut pas être suffisamment testé à l'aide de son interface publique, vous devez trouver des moyens de fournir des extensions formelles et utiles à son interface qui faciliteraient les tests. Par exemple, un système d'enregistrement avec seulement une paire de méthodes Register / Deregister bénéficierait peut-être d'une méthode IsRegistered même si elle n'est pas nécessaire pour l'application en question; néanmoins, il s'agit d'une extension formelle et utile de l'interface, et elle pourra d'ailleurs accueillir des tests.
L'important est que la modification de l'implémentation de l'objet ne devrait pas vous obliger à modifier le test unitaire. En théorie, vous devriez pouvoir écrire le test unitaire une fois, puis demander à plusieurs programmeurs de coder plusieurs implémentations entièrement différentes de l'objet à tester pour fonctionner avec le test unitaire.
la source
private
méthodesprotected virtual
pour aider à se moquer des tests est considérée comme une mauvaise pratique?En C #, vous pouvez utiliser le
InternalsVisibleToAttribute
pour permettre à votre assembly de test de voir lesinternal
classes dans l'assembly que vous testez. On dirait que vous le savez déjà.Dans la plupart des cas, je ne souhaite tester que l'API publique de mon assembly. Dans le cas où je veux faire des tests en boîte blanche d'une unité, je déplace le code dans une
internal
classe et j'en fais unepublic
méthode de cette classe. Ensuite, je peux coder un test unitaire pour cette classe.Cela se prête bien à l'injection de dépendance et au modèle de stratégie. Vous pouvez résumer la méthode dans une interface, injecter l'interface dans le constructeur de votre objet parent et tester simplement que le parent délègue de manière appropriée. Ensuite, vous pouvez tester que l'objet enfant se comporte correctement. Cela rend tout plus modulaire.
la source
D'après mon expérience, il est préférable de ne pas exposer les internes de votre classe spécialement pour le test. Même si cela peut sembler faciliter l'écriture du test. Le test est le premier client de votre classe, donc s'il est difficile de tester votre classe via son interface publique, il sera probablement difficile d'utiliser votre classe dans d'autres endroits également.
La facilité avec laquelle la classe est testée via son API publique est un retour sur la facilité d'utilisation de la classe. Considérez les tests partiellement comme un moyen de prototyper l'utilisation de votre classe.
Essayez de déterminer pourquoi votre test doit détecter quelque chose sur la classe qui n'est pas disponible via l'API publique. Peut-être que votre classe en fait trop et doit plutôt être décomposée en un groupe de classes coopérantes? Ensuite, vous pouvez vous moquer de certaines des classes collaboratrices pour détecter ce que fait la classe testée.
Essayez d'appliquer le principe d'inversion de dépendance et introduisez des interfaces entre vos classes que vous pouvez simuler dans vos tests. Vous pouvez fournir les collaborateurs à votre test en utilisant l' inversion de contrôle .
Pensez également à appliquer le principe «ne demandez pas» pour aider à structurer votre interface de classe d'une manière robuste et faiblement couplée, où les bonnes informations sont exposées et le reste est masqué.
la source
Personnellement, je préfère laisser le code que je teste aussi pur que possible et si le code de test a besoin de hacks (et en pointeurs C ++, etc.), je suis heureux de le faire.
la source
La visibilité de votre code n'a rien à voir avec vos tests unitaires!
Vous rendez vos méthodes privées et non dans le but de les cacher des tests et vous ne les rendez pas publiques pour les exposer pour le test, non? C'est votre implémentation qui est essentielle ici, pas les tests - ces serveurs comme preuve de votre code, mais ils ne sont pas votre code .
Il existe de nombreuses façons d'activer l'accès aux méthodes et propriétés cachées (privées ou internes). De nombreux frameworks de test et IDE (par exemple, Visual Studio) vous soutiennent ici en générant tout le nécessaire pour l'accès, vous n'avez qu'à créer vos cas de test. Alors, pourquoi t'inquiéter? Mieux vaut garder votre code propre et soigné.
la source