2008-12-15 9 views
5

Je travaille sur un projet où il y a beaucoup de messages de service externes. Une bonne façon de le décrire d'une manière légèrement «hyperbolique» serait une application où le système doit envoyer des messages à l'API Flicker, à l'API Facebook et à l'API Netflix. Pour prendre en charge les scénarios déconnectés, les problèmes de journalisation, la convivialité du développeur, la configuration, etc ... J'ai expérimenté une approche qui utilise fortement les génériques et les arbres d'expression. Le résultat final ressemble à ceci:Utilisation d'objets simulés en dehors des tests, mauvaise pratique?

Messenger<NetflixApi>.SendCustom(netflix => netflix.RecommendMovie("my message")); 

Je suis satisfait de l'ensemble du résultat final, mais l'impression que je l'ai fait une erreur, ou une conception principale négligé quelque part en ce qui concerne les tests et les scénarios déconnectés. Pendant les tests, automatisés, unitaires ou humains, j'ai implémenté une fabrique d'objets qui utilisait initialement DI pour effectuer l'action correcte en "mode direct" et utilisé des Mocks pour fournir une sorte de messager stérile qui ne fonctionne pas. t faire quoi que ce soit du tout quand dans un mode de test.

Je n'ai vu ou lu que des Mocks utilisés en mode TDD pur et n'étant pas utilisés comme des objets stupides. Les approches que j'ai vues tourneraient autour du stubbing ou se moquer de la fonctionnalité de communication HTTP dont dépendent toutes les API que j'utilise. Ma principale préoccupation est que tous les différents services auxquels je m'attends me feraient un travail granulaire en substituant une implémentation HTTP spécifique et si j'utilisais une approche stub, j'aurais 3 classes pour chacun de ces services (IService, ConcreteService, StubService) et le maintien de ceux-ci lors de la mise en œuvre d'une nouvelle méthode ou de tout changer serait un vrai PITA.

Dans l'implémentation actuelle, j'utilise Mocks pour obtenir gratuitement le "mode stérile" sans avoir à implémenter quoi que ce soit de plus pour se conformer à un certain principe de test.

La question est de savoir s'il me manque quelque chose? Ai-je violé un concepteur utilisant Mocks d'une manière plus ... pratique?

Quelqu'un peut-il offrir des conseils sur la façon d'obtenir un mode stérile à partir de nombreux services extérieurs différents sans passer par beaucoup de cerceaux?

Cette question a-t-elle un sens?

Merci pour toutes les réponses.

Edit # 1:

je n'étais pas clair dans ma question initiale. Tous les objets NULL ou Mock doivent être utilisés uniquement dans un environnement de développement/débogage/test. En production le code qui envoie ces messages sera l'implémentation réelle de ceux-ci.

J'ai voté pour tout le monde parce qu'il semble y avoir beaucoup de solutions différentes à ce problème et je vais explorer chacun d'eux.

S'il vous plaît ne pense pas que cette question a été répondu pour le moment, j'apprécierais autant de conseils que je peux obtenir.

Répondre

6

Il existe un motif de conception appelé Null Object. Un objet nul est un objet qui implémente une interface, il pourrait donc être utilisé dans un scénario comme le vôtre. La chose importante à propos de l'objet nul est de NE PAS retourner la valeur null là où cela pourrait casser le système.

Le but de l'objet Null est d'avoir une implémentation vide et simple de quelque chose, tout comme un Mock, mais à utiliser dans l'environnement de production.

L'exemple le plus simple est quelque chose comme ceci:

class Logger{ 
private static ILogger _Logger; 

static Logger(){ 
    //DI injection here 
    _Logger = new NullLogger(); //or 
    _Logger = new TraceLogger(); 
} 
} 

interface ILogger{ 
void Log(string Message); 
} 

internal class TraceLogger:ILooger{ 
public void Log(string Message){ 
    //Code here 
} 
} 

internal class NullLogger{ 
public void Log(string Message){ 
    //Don't don anything, in purporse 
} 
} 

J'espère que cela pourrait vous aider à

+0

La seconde fois que j'ai vu le sujet de ce fil, une alerte "Null Object" rouge s'est ... – abyx

4

Je pense que vous devrez peut-être clarifier votre question. Je ne sais pas si vous parlez d'utiliser des doubles de test dans les tests sans répéter ou tester les attentes (donc les utiliser comme faux pour répondre aux interfaces requises) ou si vous parlez d'utiliser des simulacres dans un scénario de production pour remplir des services qui ne sont pas disponibles (votre scénario déconnecté).

Si vous parlez dans des situations de test: Les mocks sont des doubles de test. Il n'y a rien de mal à tester en utilisant des contrefaçons par opposition à des faux ou des talons. Si vous n'avez pas besoin d'utiliser le service dans un test spécifique et qu'il est juste là pour fournir une interface donnée sur laquelle l'objet testé a une dépendance, alors ça va. Cela ne casse aucun principe de test.

De bonnes bibliothèques de moqueurs brouillent les lignes entre les faux-semblants, les faux-bouchons et les faux. Jetez un oeil à certaines des informations de Martin Fowler sur les différents types de doubles de test. Mocks Aren't Stubs, TestDoubles.

J'aime vraiment la façon dont moq permet un continuum entre les objets factices, faux, stub et faux sans que vous ayez besoin de passer par des cerceaux pour obtenir des comportements spécifiques. Check it out.

Si vous parlez d'utiliser des mock dans votre scénario déconnecté pour une utilisation en production ... Je serais inquiet. Un faux va retourner des objets nuls ou des valeurs par défaut pour tous les appels que vous faites. Cela entraînera une perte de complexité dans tout le code consommant ces services (ils devront gérer la vérification des valeurs de retour nulles et des tableaux vides ...). Je pense qu'il serait plus logique que votre scénario déconnecté/stérile soit codé pour gérer le fait que les dépendances elles-mêmes soient indisponibles plutôt que d'accepter des implémentations simulées de celles-ci et de continuer comme si tout fonctionnait.

4

Il me semble que vous pouvez jeter un oeil à la configuration de proxy. Vous voulez quelque chose qui agit comme divers services même si déconnecté des services réels. Par conséquent, votre code serait mieux de parler à un proxy au lieu de la vraie chose. Ensuite, le proxy peut faire tout ce dont il a besoin en fonction de l'état actuel de la connexion.

Questions connexes