Usare TDD ovunque, testare un servizio WCF - TDD everywhere, testing a WCF service

Il Test Driven Development è un’altra delle metodologie secondo me vincenti, specialmente in alcuni contesti, in alcuni, perchè non è detto che siano sempre adatte.

TDD o meglio Test Driven Design è particolamente utile quando si scrive una nuova applicazione o nuove feature nella fase di design della soluzione, partire dal test permette di tradurre al meglio la User Story o la feature (Feature Driven Development) nel codice che la implementa, si rimane concentrati sul cosa e non sul come, si scrive lo stretto necessario senza over-ingegnerizzare => “over-complicare”.

Scrivendo prima il test si identificano le classi/membri esattamente nel momento in cui servono, inoltre con i test ovviamente… si hanno i test :), si possono verificare più use-case e rendere il codice più robusto. Infine grazie agli stub ed ai mock non è indispensabile lavorare sulle classi reali anzi meglio lavorare su fake con Unit Test, invece che scrivere Integration Test. Ovviamente sono utili anche gli Integration Test ed i System Test per evitare allo sviluppatore di eseguire continuamente l’applicazione. Nonstante questo gli User Acceptance Test rimangono indispensabili, uno o più utenti devono testare l’applicazione e la UI specialmente (se esiste) perchè ovviamente è la parte maggiormente a contatto con il “ProductOwner” e probabilmente la più difficile da testare in automatico attualmente.

Arriviamo al titolo del post :). In un progetto a cui lavoro ho avuto la necessità di creare una key per una entity che fosse in realtà un’insieme di valori eterogeneo, il motivo è che lo storage è più di uno ed ogni storage può definire differenti chiavi naturali (i loro progettisti, Topolino e Paperino, non conoscono le chiavi surrogate e i Guid :D).
Topolino e Paperino DB designers

Quindi partendo dal test:

   1: public void CreateAKeyExpectedCorrectNameAndCorrectValueAreSetted()
   2: {
   3:     var concreteKey = new ConcreteKey(KnownKeys.Key);
   4:  
   5:     concreteKey
   6:         .Id
   7:         .ShouldEqual(KnownKeys.Key, "IdKey has not the expected value.");
   8: }


Quindi la classe Key:

   1: public abstract class Key : IEnumerable<KeyValue>
   2: {
   3:     private readonly IEnumerable<KeyValue> keysDictionary;
   4:  
   5:     protected Key(params KeyValue[] keyValues)
   6:     {
   7:         if ((keyValues == null) || (keyValues.Length == 0))
   8:         {
   9:             throw new ArgumentException("Must define at least a KeyValue.", "keyValues");
  10:         }
  11:  
  12:         keysDictionary = keyValues;
  13:     }
  14:  
  15:     public IEnumerator<KeyValue> GetEnumerator()
  16:     {
  17:         return 
  18:             keysDictionary
  19:             .OrderBy(keyValue => keyValue.Key)
  20:             .GetEnumerator();
  21:     }
  22:  
  23:     IEnumerator IEnumerable.GetEnumerator()
  24:     {
  25:         return GetEnumerator();
  26:     }
  27:  
  28:     protected T GetKeyValue<T>(string keyName) where T : struct
  29:     {
  30:         var value =
  31:             keysDictionary
  32:                 .Where(e => e.Key == keyName)
  33:                 .First()
  34:                 .Value;
  35:  
  36:         return (T) value;
  37:     }


Ho quindi scritto un DTO per trasportare le entity attraverso WCF e qui nasce il problema, non volendo creare un servizio WCF fittizio solo per verificare che il design sia corretto ho cercato come hostare il servizio direttamente dal test, ed ecco la soluzione: Testable WCF ServiceHost.

In sostanza grazie alla classe scritta dall’autore è possibile questo test:

   1: [TestMethod]
   2: public void CallGetAllOfWcfServiceExpectedWorksAndKeysAreSetted()
   3: {
   4:     using (var messageServiceHost = new WcfTestHost<Service, IService>())
   5:     {
   6:         var client = messageServiceHost.CreateProxy();
   7:         var dtoSet = client.GetAll().ToList();
   8:  
   9:         var keyValue = dtoSet[0]
  10:             .Key
  11:             .First();
  12:  
  13:         keyValue
  14:             .Key
  15:             .ShouldEqual(ConcreteKey.IdKeyName, "Expected a key that is not present.");
  16:  
  17:         ((int)
  18:         keyValue
  19:             .Value)
  20:             .ShouldEqual(KnownKeys.Key, "Wrong key value.");
  21:     }
  22: }


Un pezzo della classe WcfTestHost:

   1: public WcfTestHost(Binding binding)
   2: {
   3:     host = new ServiceHost(serviceImplType);
   4:     this.binding = binding;
   5:  
   6:     url = string.Format("{0}://localhost/{1}", binding.Scheme, Guid.NewGuid());
   7:     host.AddServiceEndpoint(serviceIntType, binding, url);


Nell’esempio allegato si trova il progetto della key e la classe per testare un servizio WCF completa, grazie a qualche email scambiata con l’autore, di error handling e trace che permette di intercettare qualsiasi exception scatenata “lato server”.
Solution TDD WCF 

Scarica qui.

Matteo Migliore.

Technorati Tags: ,,,
Add Comment Filed Under [ Architettura ]
Comments have been closed on this topic.