Comme l'auteur de cette question de 2012 et celle de 2013 , j'ai une bibliothèque tierce que je dois envelopper pour tester correctement mon application. La première réponse indique:
Vous voulez toujours envelopper les types et méthodes tiers derrière une interface. Cela peut être fastidieux et douloureux. Parfois, vous pouvez écrire un générateur de code ou utiliser un outil pour ce faire.
Dans mon cas, la bibliothèque est pour un modèle d'objet et a par conséquent un plus grand nombre de classes et de méthodes qui devraient être encapsulées pour que cette stratégie réussisse. Au-delà de simplement "fastidieux et douloureux", cela devient une barrière difficile à tester.
Au cours des 4 années qui se sont écoulées depuis cette question, je suis conscient que les cadres d'isolement ont beaucoup progressé. Ma question est la suivante: existe-t-il maintenant un moyen plus simple d'obtenir l'effet d'un habillage complet des bibliothèques tierces? Comment puis-je éliminer la douleur de ce processus et réduire l'effort manuel?
Ma question n'est pas un double des questions auxquelles j'ai initialement lié, car la mienne concerne la réduction de l'effort manuel d'emballage. Ces autres questions ne demandent que si l’emballage a du sens, pas comment l’effort peut être limité.
la source
Réponses:
En supposant que vous ne recherchiez pas un cadre moqueur, car ils sont ultra-omniprésents et faciles à trouver , il y a quelques choses à noter à l'avance:
Il n'est pas toujours préférable de conclure une bibliothèque tierce. Si votre application est intrinsèquement dépendante d'une bibliothèque, ou si elle est littéralement construite autour d'une ou deux bibliothèques principales, ne perdez pas votre temps à la boucler. Si les bibliothèques changent, votre application devra quand même changer .
Cela est particulièrement vrai autour des limites qui sont stables, intrinsèques à votre application ou qui ne peuvent pas être facilement moquées. Si ces conditions sont remplies, l'emballage et la moquerie seront compliqués et fastidieux. Dans ce cas, j'éviterais les deux: ne pas envelopper et ne pas se moquer; il suffit d'écrire des tests d'intégration. (Si les tests automatisés sont un objectif.)
En principe, un outil ne peut couper que sur le passe-partout. Mais, il n'y a pas d'algorithme automatisable pour prendre une interface complexe et la rendre simple - sans parler de prendre l'interface X et de l'adapter à vos besoins. (Vous seul connaissez cet algorithme!) Donc, même s'il existe sans aucun doute des outils qui peuvent générer des wrappers fins, je dirais qu'ils ne sont pas déjà omniprésents car, en fin de compte, vous devez toujours coder intelligemment, et donc manuellement, contre l'interface même si elle est cachée derrière un wrapper.
Cela dit, il existe des tactiques que vous pouvez utiliser dans de nombreuses langues pour éviter de vous référer directement à une classe. Et dans certains cas, vous pouvez «simuler» une interface ou un wrapper mince qui n'existe pas réellement. En C #, par exemple, je choisirais l'une des deux voies:
Vous pouvez éviter l'effort d'encapsuler complètement une classe complexe avec ce petit combo:
Si vous pouvez éviter de stocker ces objets en tant que membres, soit par une approche plus "fonctionnelle", soit en les stockant dans un dictionnaire (ou autre ), cette approche a l'avantage de vérifier le type au moment de la compilation sans que vos entités métier principales n'aient besoin de savoir exactement avec quelle classe ils travaillent.
Tout ce qui est requis, c'est qu'au moment de la compilation, la classe renvoyée par votre fabrique contient en fait les méthodes que votre objet métier utilise.
C'est dans la même veine que l'utilisation du typage implicite , mais implique un autre compromis: vous perdez les vérifications de type compilation et avez la possibilité d'ajouter anonymement des dépendances externes en tant que membres de la classe et injectez vos dépendances.
Avec ces deux tactiques, quand vient le temps de se moquer
ExternalPDFLibraryDocument
, comme je l'ai dit plus tôt, vous avez du travail à faire - mais c'est un travail que vous devez faire de toute façon . Et, avec cette construction, vous avez évité de définir fastidieusement des centaines de petites classes de wrapper minces. Vous avez simplement utilisé la bibliothèque sans la regarder directement - pour la plupart.Cela dit, il y a trois grandes raisons pour lesquelles j'envisagerais toujours de conclure explicitement une bibliothèque tierce - aucune ne suggérant l'utilisation d'un outil ou d'un framework:
Si je n'ai pas un certain niveau de préoccupation dans ces trois domaines, vous ne faites aucun effort important pour conclure. Et, si vous avez des inquiétudes dans les trois domaines, un wrapper mince généré automatiquement ne va pas vraiment aider.
Si vous avez décidé de conclure une bibliothèque, l'utilisation la plus efficace et la plus efficace de votre temps est de créer votre application avec l'interface que vous souhaitez ; pas contre une API existante.
Autrement dit, tenez compte du conseil classique: reporter toutes les décisions que vous pouvez. Créez d'abord le «cœur» de votre application. Codez contre des interfaces qui finiront par faire ce que vous voulez, qui seront finalement remplies par des "choses périphériques" qui n'existent pas encore. Comblez les lacunes au besoin.
Cet effort peut ne pas ressembler à un gain de temps; mais si vous sentez que vous avez besoin d'un emballage, c'est le moyen le plus efficace de le faire en toute sécurité.
Pense-y de cette façon.
Vous devez coder par rapport à cette bibliothèque dans un coin sombre de votre code - même s'il est terminé. Si vous vous moquez de la bibliothèque pendant les tests, il y a inévitablement un effort manuel - même si elle est terminée. Mais cela ne signifie pas que vous devez reconnaître directement cette bibliothèque par son nom dans la majeure partie de votre application.
TLDR
Si la bibliothèque vaut la peine d'être emballée, utilisez des tactiques pour éviter les références directes et étendues à votre bibliothèque tierce, mais ne prenez pas de raccourcis pour générer des enveloppes minces. Construisez d'abord votre logique métier, réfléchissez à vos interfaces et sortez vos adaptateurs de manière organique, au besoin.
Et, si cela arrive, n'ayez pas peur des tests d'intégration. Ils sont un peu plus flous, mais ils offrent toujours des preuves de fonctionnement du code, et ils peuvent toujours être facilement effectués pour garder les régressions à distance.
la source
Ne testez pas ce code à l'unité. Écrivez plutôt des tests d'intégration. Dans certains cas, les tests unitaires, moqueurs, sont fastidieux et douloureux. Abandonnez les tests unitaires et écrivez des tests d'intégration qui font réellement appel au fournisseur.
Remarque, ces tests doivent être exécutés après le déploiement en tant qu'activité automatisée post-déploiement. Ils ne sont pas exécutés dans le cadre de tests unitaires ou dans le cadre du processus de génération.
Parfois, un test d'intégration est mieux adapté qu'un test unitaire dans certaines parties de votre application. Les cerceaux que l'on doit traverser pour rendre le code "testable" peuvent parfois être préjudiciables.
la source
Si je comprends bien, cette discussion se concentre sur les opportunités d'automatisation de la création d'encapsuleurs plutôt que sur l'idée d'encapsulation et les directives d'implémentation. J'essaierai de m'abstraire de l'idée car il y en a déjà beaucoup ici.
Je vois que nous jouons autour des technologies .NET, nous avons donc de puissantes capacités de réflexion entre nos mains. Vous pouvez envisager:
Je pense qu'une telle automatisation peut constituer un point de base, mais pas une solution définitive. Une refactorisation manuelle du code sera nécessaire ... ou dans le pire des cas une refonte car je suis entièrement d'accord avec ce que svidgen a écrit:
la source
Suivez ces instructions lors de la création de bibliothèques d'encapsuleurs:
la source