2013-04-10 19 views
6

ho questo:Come rendere la classe più testabile?

class FooGenerator:IFooGenerator { 
     private object _generated; 

     public void Generate() { 
     // Generating 
     GenerateSmallPart(); 
     GenerateOtherSmallPart(); 
     GenerateTinyPart(); 
     // A lot similar 
     } 

     private void GenerateSmallPart() { 
     //add small part to _generated 
     } 

     private void GenerateOtherSmallPart() { 
     //add small part to _generated 
     } 

     private void GenerateTinyPart() { 
     //add small part to _generated 
     } 
    } 

    internal interface IFooGenerator { 
     void Generate(); 
    } 

Nella mia applicazione uso solo IFooGenerator via CIO, ma voglio provare tutti quei metodi secondari.

Come ho trovato here, un'opzione è di estrarre la classe con tutti i metodi secondari. Ma perché ho bisogno di farlo. Viene utilizzato solo in FooGenerator.

Avete qualche suggerimento come posso rendere più testabile la mia lezione?

+9

Per quanto ne so, si dovrebbe provare contro l'API pubblica, non quella interna, quindi è necessario testare "IFooGenerator.Generate" e verificare se il risultato è quello che ci si aspetterebbe. Ma se vuoi davvero testare la parte 'costruzione', forse è una buona idea estrarre le parti 'Genera' in un costruttore ...? –

+0

Dato che tutti quei metodi non restituiscono nulla, mi chiedo come li vuoi testare comunque ... Stai usando Mock? Se è così, puoi verificarli anche quando testi solo il metodo pubblico. Ma attenzione: questo molto probabilmente crea test fragili. –

+0

:) Sì! inizia un po 'di black box/white box testing flamewar :) Per me IL MEDICO ha ragione. – wonko79

risposta

1

Chi è il cliente?

Molte persone (Roy Osherove, Michael Feathers) considerano il client di prova altrettanto valido dell'interfaccia o del client di servizio.

Con questo in mente penso che va bene andare leggermente contro il principio di incapsulamento aprendo le cuciture testabili rendendo pubblici alcuni metodi privati.

+0

Voglio solo aggiungere che se stai andando contro l'incapsulamento nel nome della testabilità allora ti consiglio di rendere alcuni metodi privati ​​interni e di aggiungere l'assembly unit test ai tuoi amici con l'attributo [InternalsVisibleTo] (http : //msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx). –

+0

@ aleksey.berezan questo attributo InternalsVisibleTo mi sembra una soluzione alternativa. Davvero non voglio andare contro i sacri principi :) –

2

Condividerò con voi come gestisco questa situazione. Se vedo che voglio testare alcuni metodi privati ​​per qualche ragione (come se fosse difficile bloccare i parametri di input per testare tutti i flussi di codice), questo di solito significa che la complessità della mia classe è alta e ho bisogno di rifattorizzare il mio codice. Nel tuo caso (non ho idea di che cosa i vostri metodi stanno facendo) si può usare qualcosa di simile a:

interface IPartGenerator 
{ 
    void GeneratePart(); 
} 

class SmallPartGenerator : IPartGenerator 
{ 
    void GeneratePart(); 
} 

class OtherSmallPartGenerator : IPartGenerator 
{ 
    void GeneratePart(); 
} 

class TinyPartGenerator : IPartGenerator 
{ 
    void GeneratePart(); 
} 

class FooGenerator:IFooGenerator 
{ 
    private IPartGenerator[] partGenerators = new IPartGenerator[] 
         { 
          new SmallPartGenerator(), 
          new OtherSmallPartGenerator(), 
          new TinyPartGenerator() 
         } 

    public void Generate() 
    { 
     foreach (var partGenerator in partGenerators) 
     { 
       partGenerator.GeneratePart(); 
     } 
    } 
} 

Ora è possibile testare ciascuno dei generatori parte separatamente.

0

La classe non ha una cosa, ma molte cose, ciascuna incapsulata in un metodo privato. Questa è una violazione del Single Responsibility Principle (SRP). Secondo SRP, una classe dovrebbe fare solo una cosa.

Neil Thompson suggerisce di rendere pubblici i metodi privati. Questo, almeno, li rende accessibili ai test unitari, ma sono ancora violazioni SRP. Se la tua classe ha molte cose diverse, l'iniziazione è spesso complessa; devi creare la classe in uno stato che soddisfi le esigenze di tutti i metodi, sebbene tu voglia solo testare un piccolo angolo. Questo non fa niente per la testabilità.

In seguito a ciò, la risposta di un operatore esterno è un progetto più solido. Il suo codice non ha violazione SRP.

+0

Si avvicina Builder che è stato suggerito da Trust me - I'm a Doctor viola l'SRP? –

+0

A mio parere, la tua classe ha ancora molte R diverse (responsabilità) con l'approccio gentile dei dottori. SRP significa solo una R per classe, quindi sì, viola SRP. Una volta che hai approfondito il test di unità/TDD, vedrai quanto è prezioso SRP. – Morten

Problemi correlati