Espando un pochino il concetto espresso nel precedente post a beneficio di chi sia ignaro della questione
Nel mio caso specifico, ho la necessità di connettermi ad un servizio remoto
che mi restituisce un documento XML, che viene poi a sua volta interpretato per
creare una serie di entities del mio object model. La classe di cui può
avvalersi l'utilizzatore per ottenere le previsioni del tempo accetta nel
costruttore un oggetto di tipo IWeatherConnector, che sarà poi fisicamente
responsabile di inviare una richiesta Http, ottenere una risposta e restituire
l'XML di processare:
public class WeatherProvider: IWeatherProvider
{
public WeatherProvider(IWeatherConnector connector)
{
....
}
public CurrentConditions GetCurrentConditions
(string locationId, UnitType unitType)
{
// metodo da testare, in cui utilizzo l'istanza di
// IWeatherConnector passata nel costruttore
}
public Forecast[] GetForecasts
(string locationId, UnitType unitType, int days)
{
// altro metodo da testare... stesse caratteristiche
// del precedente
}
}
Ora... nel mio Unit Test voglio verificare che il metodo
GetCurrentConditions riesca ad effettuare il parsing dell'XML in maniera
corretta, restituendo l'istanza di CurrentConditions che mi aspetto. Come posso
fare? sicuramente non posso collegarmi ogni volta a Weather.com per eseguire i
test, perché il collegamento potrebbe essere down, il mio test fallirebbe,
otterrei un rosso, ma il mio metodo magari funziona benissimo, avrei quindi un
test dal risultato *NON DETERMINISTICO* perché influenzato da fattori
esterni!
Cosa fare allora? ho bisogno di un Mock Object, di un IWeatherConnector
fittizio che mi permetta di isolare la mia classe e di testarla
autonomamente. Ho usato NMock (perché avevo già un piccolo esempio di Andrea, come detto),
in realtà ne esistono altri, tra cui Rhino-Mocks del bravo Ayende Rahien
(sì, lo stesso di NHibernate Query Analyzer). NMock dicevo... bene... lo uso nella
Fixture per costruire il mio connector fasullo:
private IWeatherConnector getWorkingConnector(string expectedResponse)
{
DynamicMock mockGenerator = new DynamicMock(typeof(IWeatherConnector));
XmlDocument resp = new XmlDocument();
resp.LoadXml(expectedResponse);
mockGenerator.SetupResult("InvokeService", resp, new Type[] { typeof(string) });
return (IWeatherConnector) mockGenerator.MockInstance;
}
Con 5 (CINQUE) righe di codice, dico a NMock di generare un tipo che
implementi IWeatherConnector, così che possa usarlo nel costruttore
della classe da testare, e che, eseguendo il metodo InvokeService restituisca la
risposta expectedResponse specificata come parametro. E se volessi
controllare come si comporta la mia classe under test se il connector solleva
un'eccezione?
private IWeatherConnector getBrokenConnector()
{
DynamicMock mockGenerator = new DynamicMock(typeof(IWeatherConnector));
mockGenerator.ExpectAndThrow("InvokeService",
new TimeoutException(), new Type[] { typeof(string) });
return (IWeatherConnector)mockGenerator.MockInstance;
}
Ora dico al mockGenerator che l'istanza generata deve sollevare una
TimeoutException ad ogni esecuzione del metodo
InvokeService!
Mica male, eh?
powered by IMHO 1.3