Domanda

Un mese fa ho finito di leggere il libro "L'arte dello unit test" e oggi ho finalmente avuto il tempo di iniziare a utilizzare Rhino Mocks con lo unit testing un servizio che invia/riceve messaggi ai dispositivi (UDP) e salva/carica dati dal database.
Ovviamente voglio isolare il database e la comunicazione UDP.

Ad esempio per l'accesso al database, abbiamo alcune classi con metodi statici, chiamiamole:

  • AccessoAreaADB
  • AccessoAreaBDB
  • AccessoAreaCDB

Queste classi avevano metodi statici che eseguivano l'accesso al database.
Per poterli stordire ho reso pubblici i loro metodi virtuali.

Quindi ho iniziato a rifattorizzare il codice per poter sostituire l'istanza di queste classi sul codice.
Dopo aver provato cose diverse, mi sono ritrovato con un corso di fabbrica che sembra rendere le cose così facili.

public class ObjectFactory
{
    private static Dictionary<Type, object> Instances = new Dictionary<Type, object>();

    public static T GetInstance<T>() where T : new()
    {
        if(Instances.ContainsKey(typeof(T)))
            return (T)Instances[typeof(T)];

        return new T();
    }

    public static void SetInstance<T>(object obj)
    {
        Instances[typeof(T)] = obj;
    }
}

Quindi sul codice, posso usare

private AreaADBAccess DBAccess = ObjectFactory.GetInstance<AreaADBAccess>();

E sul metodo di prova faccio qualcosa del genere

AreaADBAccess dbAccess = mocks.Stub<AreaADBAccess>();
using (mocks.Record())
{
...
}
ObjectFactory.SetInstance<AreaADBAccess>(dbAccess);
//Invoke the test method
...

Questa è una prima soluzione e mi rendo conto che si può fare in modo migliore.
Puoi ora commentarlo e indicarmi le migliori pratiche?
Potete anche spiegarmi perché vorrei avere un'interfaccia invece di definire i metodi come virtuali?Sembra inutile ripetere le intestazioni del metodo in 2 punti.
Grazie!

È stato utile?

Soluzione

Probabilmente potresti avvalerti di contenitori IoC come Windsor, StructureMap o Ninject, che ti renderebbero la vita molto più semplice, ed infatti funzionano anche come "factory" che hai creato manualmente, ma sono molto più potenti.

Inoltre ci sono contenitori automocking che creeranno automaticamente dipendenze fittizie per le tue classi in modo da poter salvare ulteriori righe di codice e rendere il tuo test meno fragile.

Per quanto riguarda la domanda riguardante la necessità di un'interfaccia anziché di classi, si tratta fondamentalmente del principio di inversione delle dipendenze, che afferma che i moduli (classi) di livello superiore non dovrebbero dipendere da moduli (classi) di livello inferiore, entrambi dovrebbero dipendere da astrazioni.Le interfacce sono quelle astrazioni.Ti suggerisco di dare un'occhiata ai principi S.O.L.I.D che ti renderanno la vita molto più semplice, almeno l'hanno fatto con me..

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top