Je veux tester en unité une méthode d'extension...
Le site string HostName()
La méthode que vous avez postée est une fonction triviale : Je ne pense pas qu'il soit utile d'écrire un quelconque code de test pour cela. .
Les tests automatisés sont formidables, mais ils introduisent leur propre fragilité et leur propre charge de maintenance. S'il vous a fallu 3 minutes pour rechercher et écrire cette fonction, il vous faudra désormais beaucoup plus de minutes supplémentaires pour réfléchir à tous les différents cas de figure étranges et exotiques où votre HostName
échouera (par exemple, la fonction website.Data is null
dans une situation obscure de réseau ou de condition de course).
Ne pas tenir compte de cela spécifique mais d'une manière générale : en ce qui concerne la manière de concevoir testable du code qui consomme directement des objets provenant de bibliothèques externes opaques... eh bien, la réponse simple est la suivante Ne le fais pas. (comme dans : n'écrivez pas de code d'application qui consomme directement des objets de bibliothèques externes et qui passe directement ces objets plus loin dans votre propre code d'application ).
Alors, mettez plutôt en place des limites claires : cloisons logicielles entre des composants distincts dans le code de votre application et ne laissez jamais un objet externe nu franchir cette ligne. Si vous avez besoin de faire passer des données d'une bibliothèque externe à travers la ligne, alors introduisez l'option votre propre POCO data-transfer-object et copier les valeurs dedans, puis passer que le long.
L'alternative chemin de moindre résistance n'aboutit qu'à de plus mauvais résultats à long terme : au bout du compte, chaque projet de votre solution doit référencer tous les mêmes paquets NuGet et les mêmes références d'assemblage afin que les objets de bibliothèque externes puissent être transmis (par exemple, en transmettant le fichier WebSiteResource
jusqu'à votre interface utilisateur).
.... alors vous rencontrerez de plus en plus de problèmes comme ceux que vous avez illustrés : même si c'est votre projet vous n'avez plus aucun contrôle réel sur les objets opaques que vous utilisez : afin d'accomplir un objectif futur, vous vous retrouverez probablement à combattre ces librairies et à devoir écrire du code pirate pour les contourner au lieu de simplement éditer directement leur source et les recompiler, parce que vous ne les contrôlez pas.
Aparté : Personnellement, je blâme le système de type inflexible de C#...
Je note qu'une grande partie de ce problème est simplement dû à la façon dont C# et le CLR .NET fonctionnent : cela en fin de compte, vous ne pouvez pas manipuler cette WebSiteResource
(et ses objets-instances) par le système de type .NET. (...au moins en Java, tout est <code>virtual</code> ) .
Parce que C#/.NET utilise un système de type nominatif qui est strictement appliqué par le runtime, et parce qu'il ne supporte pas le typage structurel ou les véritables types algébriques, cela signifie que nous ne pouvons pas faire des choses comme class HahahImSubclassingYouAnyway extends WebSiteResource
(ou même class HahahImSubclassingYouAnyway implements WebSiteResource
dans certaines langues). Au moins, nous pouvons utiliser la composition (que nous devrait Mais une fois de plus, C#/.NET traîne encore les pieds lorsqu'il s'agit de faciliter la composition de types, sans parler de la façon dont il est possible d'utiliser l'outil de composition. impossible pour maintenir l'identité de la référence (c'est pourquoi nous sommes obligés d'utiliser la sous-classification basée sur l'héritage dans certaines situations).
Bref, je divague...
Je ne peux pas me moquer WebSiteResource
parce qu'il ne s'agit pas d'une interface
- En supposant que vous Je suis toujours d'accord avec ça. puis implémentez vos propres types d'adaptateurs.
- Oui, c'est exactement aussi fastidieux et source d'erreurs que ça en a l'air.
-
Oui c'est pourquoi c'est probablement une utilisation inappropriée de votre temps de travailler sur ce sujet.
Je ne peux pas instancier WebSiteResource
parce que la propriété Data
nécessite une configuration complexe
Le fait que vous ayez écrit cela donne l'impression que vous envisagez d'écrire des cas de test qui testeront essentiellement le WebSiteResource
bien plus que votre propre code. Je sais que ce n'est pas votre intention, cependant.
Je ne peux pas créer un MockableWebSiteResource
qui hérite de WebSiteResource
(et faire quelque chose comme public new virtual Data { get; set; }
) car Data
nécessite une configuration complexe
Whoa, stop, Ne bougez pas. ...
Ce que vous décrivez est un abus de l'héritage OOP. Votre proposition MockableWebSiteResource
ne devrait clairement pas avoir de relation conceptuelle "est" avec WebSiteResource
mais c'est exactement ce que représente l'héritage des classes dans le cadre de la POO. WebSiteResource
représente une mise en œuvre de service complète, et non un service abstrait). C'est un signe que quelque chose ne va pas avec votre approche. Arrêtez. Réfléchissez. Reconsidérez la situation.
(Et parce que Java -L'héritage OOP de style (que C# partage) est si limitatif et inélégant qu'il finit juste par créer les problèmes au lieu de les résoudre : c'est tout simplement mauvais . Je suis sûr que vous avez rencontré des situations où il était impossible d'utiliser l'héritage de la POO pour tout type d'activité directe. modélisation de domaine ).
(Avec mes excuses aux fans de Smalltalk et de Simula (nous vous aimons), mais j'utilise le terme "POO" dans le sens de la famille Java : je ne fais donc pas référence à l'approche plus large (ou à la <em>plus pur </em>) les concepts supérieurs de la POO O.G. où le passage de messages et la délégation sont utilisés au lieu des méthodes virtuelles et de l'héritage)
Comment concevoir des méthodes pour éviter de les rendre non testables ?
Je ne peux rien vous donner d'autre que des directives générales que nous avons tous déjà données :