Ho letto recentemente un articolo in cui si diceva che gli oggetti finti sono spesso fraintesi e mal utilizzati. Esistono degli anti-schemi di derisione chiari che posso cercare?
Detesto vedere semplici classi concrete derise. Ad esempio, prendi la seguente classe semplice che non ha dipendenze da nient'altro:
public class Person
{
private readonly string _firstName;
private readonly string _surname;
public Person(string firstName, string surname)
{
if (String.IsNullOrEmpty(firstName))
{
throw new ArgumentException("Must have first name");
}
if (String.IsNullOrEmpty(surname))
{
throw new ArgumentException("Must have a surname");
}
_firstName = firstName;
_surname = surname;
}
public string Name
{
get
{
return _firstName + " " + _surname;
}
}
}
In tutti i test che coinvolgono questa classe, preferirei che uno di quelli reali fosse istanziato e usato piuttosto che un'interfaccia come "IPerson", una beffa usata e le aspettative impostate su. Usando quello reale il tuo test è più realistico (hai i parametri di verifica in atto e la reale implementazione della proprietà 'Name'). Per una classe semplice come questa non stai facendo i tuoi test più lenti, meno deterministici o infangando la logica (non è probabile che tu abbia bisogno di sapere che Nome è stato chiamato quando collaudi un'altra classe) - che sono le solite ragioni per deridere / stubbing.
Come estensione a questo ho anche visto persone scrivere test in cui la simulazione è impostata con un'aspettativa, quindi la simulazione viene chiamata direttamente nel test. Insolitamente il test passerà sempre ... hmmmm ...
Potrebbe sembrare ovvio, ma: non utilizzare oggetti finti nel codice di produzione! Ho visto più di un esempio in cui il codice di produzione dipendeva dalle caratteristiche di determinati oggetti mock ( MockHttpServletRequest
da Springframework per esempio).
Secondo me è il controllo eccessivo del metodo di chiamata sui mock. Ritengo che questa sia una pratica applicata da alcuni framework di simulazione come EasyMock, in cui il comportamento predefinito di mock è fallire ogni volta che c'è un richiamo di un metodo aggiuntivo rispetto a ciò che non era esattamente specificato prima. Questo tipo di rigoroso controllo del metodo simulato può portare a progetti fragili in cui il più piccolo cambiamento al codice può portare a un'intera suite di test che non riescono, anche se la funzionalità di base è sempre la stessa.
Una soluzione a questo sta iniziando a usare stub invece di mock. Un articolo che ho trovato particolarmente illuminante sull'argomento è stato trovato in Javadoc di Mockito: link (vedi "2. Che ne dici di alcuni stub?"), che collega a: link .
Mi è piaciuto lavorare con Mockito finora perché non impone questo rigido comportamento di derisione ma l'uso di stub. Impone anche il controllo del metodo su quelli specifici invece dell'intero oggetto fittizio; così finisci per controllare solo i metodi che contano davvero nello scenario di test.
Ci sono alcuni libri qua e là che posso consigliare di toccare questo argomento e di prendere in giro e in generale:
xModifica di unità
The Art of Unit Testing: con esempi in .Net
Test Java di prossima generazione: TestNG e Advanced Concepts (questo libro riguarda principalmente testNG, ma c'è un bel capitolo sulla simulazione)
Ho osservato alcuni anti-pattern nella mia esperienza.
Altrimenti la mia esperienza con i mock soprattutto Mockito è stata un gioco da ragazzi. Hanno reso i test molto facili da scrivere e mantenere. Il test dell'interazione GWT / presentatore è molto più semplice con i mock rispetto a GWTTestCase.
Trovo che i test che utilizzano i mock su più livelli di un'applicazione siano particolarmente difficili da decifrare e modificare. Tuttavia penso che questo sia stato mitigato negli ultimi anni da API di framework mock migliorate (io uso JMock dove conveniente).
5 o 6 anni fa API come EasyMock erano potenti ma molto ingombranti. Spesso il codice di prova che ne faceva uso era di ordine di grandezza più complicato del codice che stava testando. Allora ho cercato di influenzare i team in cui mi trovavo per usarlo con parsimonia e accontentarmi di semplici mock artigianali che erano semplicemente implementazioni alternative di interfacce specifiche per i test.
Recentemente le mie forti opinioni su questo argomento sono diventate più sfumate mentre le API di simulazione hanno reso più leggibili i test che li utilizzano. Essenzialmente voglio che il mio codice (compresi i test) sia intercambiabile da altri sviluppatori senza farli sentire come se stessero setacciando una melodia di oscure chiamate API.
Leggi altre domande sui tag tdd testing anti-patterns object-oriented-design mocking