2010-12-14 6 views
0

Besoin d'aide pour l'unification. (Supposons que je n'ai pas de TypeMock)Comment voulez-vous Unitest ce code?

Voulez-vous modifier le code afin d'injecter des substituts pour substituer EndpointAddress, DiscoveryEndpoint, DiscoveryClient?

Quel genre de tests écrivez-vous? Je peux penser à

GetService_ServiceExist_ResultShouldBeAnInstance

GetService_ServiceIsNotExist_ResultShouldNull

static public T GetService<T>(Binding binding, string address) 
    { 
     Contract.Requires(binding != null); 
     Contract.Requires(!string.IsNullOrWhiteSpace(address)); 

     var endpointAddress= new EndpointAddress(address); 
     var discoveryEndpoint = new DiscoveryEndpoint(binding, endpointAddress); 

     var discoveryClient = new DiscoveryClient(discoveryEndpoint); 

     try 
     { 
      // Find ICalculatorService endpoints    
      FindResponse findResponse = discoveryClient.Find(new FindCriteria(typeof(T))); 

      Contract.Assume(findResponse != null); 
      Contract.Assume(findResponse.Endpoints != null); 


      // Check to see if endpoints were found, if so then invoke the service.);); 
      if (findResponse.Endpoints.Count > 0) 
      { 
       Contract.Assume(findResponse.Endpoints[0] != null); 

       return ChannelFactory<T>.CreateChannel(new BasicHttpBinding(), 
                    findResponse.Endpoints[0].Address); 
      } 
     } 
     catch (TargetInvocationException ex) 
     { 
      Console.WriteLine("This client was unable to connect to and query the proxy. Ensure that the proxy is up and running: " + ex); 
     } 
     return default(T); 
    } 

Appréciez toute votre aide. Merci!

Ariel

Répondre

1

Vous avez une dépendance à l'égard EndpointAddress, DiscoveryEndpoint et DiscoveryClient dans votre méthode.

Tout d'abord, je mettrais ce code dans quelque chose ressemblant à une usine. Je mettrais également les dépendances ci-dessus dans des usines si nécessaire, puis injecterais ces usines dans la classe en utilisant IOC. Ensuite, cela me permet de mettre de faux objets (ou de faux) dans le système pour les tests unitaires et je n'ai pas besoin de compter sur un déclencheur concret (par exemple). Mais si ce n'est pas un problème, je l'usine toujours.

Vous cherchez également à trouver un point de terminaison et à créer un canal ou à déclencher une exception. Eh bien, si vous restez avec ce qui précède, avez-vous besoin de revenir par défaut (T). Le choix ici est soit de garder le code là-bas puis de lancer l'exception plutôt que de renvoyer la valeur null, de la rendre nulle et de la tester, de faire cette seule chose qui est de tenter de créer un canal basé sur un DiscoveryClient. Si je le faisais, je supprimerais toutes ces dépendances, en ferais une usine (et les autres des usines si nécessaire), passerais ensuite dans un DiscoveryClient configuré et renverrait null ou retournerais une instance de NullChannel.

Ensuite, je peux faire une affirmation sur l'instance retournée dans mon test et la méthode de création n'a qu'une responsabilité.

HTH

+0

Ne pensez-vous pas que les dépendances IoC ici pourraient polluer l'API? – ArielBH

+0

Sincèrement non. Le code que vous avez repose sur d'autres composants de votre système. Alors pourquoi ne pas exprimer explicitement cette confiance en les passant par le constructeur? Si rien d'autre, vous pouvez créer manuellement ces éléments, mais même alors, si vous êtes je envisagerais d'utiliser des usines pour le faire pour vous. Jusqu'à vous vraiment - vous n'avez pas besoin d'utiliser IOC, mais si vous avez affaire à quelque chose de complexe, alors je l'utiliserais. – Simon

+0

Simon, merci. Refactoring maintenant. Je vais prendre du recul à partir d'une api statique ... (btw j'utilise un conteneur IoC ...) – ArielBH