2010-02-16 18 views
6

Se dovessi scrivere una libreria di derisione, come funzionerebbe (in altre parole, come funzionano "?")Come funzionano i framework mock?

Una delle cose che mi chiedo è che si stanno sempre impostando le aspettative, quindi è davvero necessario per confrontare l'aspettativa di ciò che il metodo fa in fase di esecuzione, quindi presumo la riflessione (risoluzione dei tipi in fase di esecuzione).

Inoltre, quando si usa il termine "oggetto mock", l'oggetto viene stubato o sarebbe un oggetto con aspettative preimpostate?

Quando penso a come scriverei la mia implementazione di una struttura/tecnica, come oggetti finti, mi rendo conto di quanto io sappia davvero (o non lo so sapere) e su cosa vorrei intervenire: se l'oggetto finto è pre-programmato per restituire le aspettative stabilite e non si chiama l'oggetto reale effettivo, il risultato non sarebbe sempre lo stesso? Ad esempio:

[TestMethod, Isolated] 
public void FakeReturnValueByMethodArgs() 
{ 
    var fake = Isolate.Fake.Instance<ClassToIsolate>(); 
    // MethodReturnInt will return 10 when called with arguments 3, "abc" 
    Isolate.WhenCalled(()=> fake.MethodReturnInt(3, "  abc")).WithExactArguments().WillReturn(10); 
// MethodReturnInt will return 50 when called with arguments 3, "xyz" 
    Isolate.WhenCalled(()=> fake.MethodReturnInt(3, "xyz")).WithExactArguments().WillReturn(50); 

    Assert.AreEqual(10, fake.MethodReturnInt(3, "abc")); 
    Assert.AreEqual(50, fake.MethodReturnInt(3, "xyz")); 

}

sarebbe non questo ritorno sempre vero?

risposta

8

L'idea con i framework di simulazione è di prendere in giro le dipendenze e non le classi effettive in prova. Per il tuo esempio, il tuo test tornerà sempre true, perché in realtà stai solo testando il framework di simulazione e non il tuo codice reale!

Un vero e finto mondo sarebbe più simile a questo:

[TestMethod, Isolated] 
public void FakeReturnValueByMethodArgs() { 
    var fake = Isolate.Fake.Instance<DependencyClass>(); 
    // MethodReturnInt will return 10 when called with arguments 3, "abc" 
    Isolate.WhenCalled(()=> fake.MethodReturnInt(3, "abc")).WithExactArguments().WillReturn(10); 

    var testClass = new TestClass(fake); 
    testClass.RunMethod(); 

    // Verify that the setup methods were execute in RunMethod() 
    // Not familiar with TypeMock's actual method to do this... 
    IsolatorExtensions.VerifyInstanceWasCalled(fake); 

    // Or assert on values 
    Assert.AreEqual(10, testClass.AProperty); 
} 

Si noti come il mock viene passato nella TestClass ed un metodo run su di esso.

È possibile leggere The Purpose of Mocking per avere un'idea migliore di come funziona il mocking.


Aggiornamento: spiegazione del perché si sta testando solo il quadro di scherno:

Quello che hai fatto è creare un metodo MethodReturnInt con il quadro di scherno con Isolate.WhenCalled().Quando si chiama MethodRecturnInt nel Assert, il codice verrà eseguito il delegato () => fake.MethodReturnInt() e tornare 10. Il quadro di scherno sta creando in modo efficace un metodo (anche se in modo dinamico), che sarebbe simile a questa:

public void MethodReturnInt(int value, string value2) { 
    Assert.Equal(3, value); 
    Assert.Equal("abc", value2); 
    return 10; 
} 

E 'un po' più complicato di quello, ma questa è l'idea generale. Dato che non esegui mai alcun codice diverso dalla creazione di 2 metodi e poi asserzioni su questi due metodi, non stai testando il tuo codice e quindi testando solo il framework di simulazione.

+0

Grazie. Puoi spiegare come il codice che ho fornito verifica la struttura di derisione e il codice reale (forse sono un po 'lento)? – dotnetdev

+0

Grazie per quello. Potrei avere un metodo che si basa su una certa data/ora per eseguire un'azione, ma cosa succede se il mio metodo restituisce effettivamente l'ora corrente (l'essenza del metodo è qualcosa che viene solitamente deriso)? Come posso testarlo? Se un metodo fa qualcosa alle 12, provo il "qualcosa", ma se il mio metodo restituisce il tempo, come posso testarlo? – dotnetdev

+0

@dotnetdev - Dai un'occhiata a questa domanda SO: http://stackoverflow.com/questions/565289/unit-testing-code-that-does-date-processing-based-on-todays-date/565314#565314 Effectively è necessario interrompere la dipendenza DateTime nel codice –

0

Sì, restituirà sempre true. Gli oggetti Mock dovrebbero essere utilizzati quando la classe sottoposta a test richiede un'altra implementazione di classe che non si desidera coinvolgere nell'esecuzione del test. Questo è molto utile quando si tratta di una classe che utilizza interfacce con più implementazioni o ci sono servizi complessi/costosi/esterni che non si desidera configurare.

Nel codice precedente, stai prendendo in giro la classe che stai "testando".

Un altro modo di pensarci è che i comportamenti falsi che si registrano sono asserzioni di black-box (implementazione), dove Assert.* sono asserzioni di white-box (api).

+0

Visto in un altro modo, gli oggetti finti sono solo un altro livello di riferimento indiretto sopra il ritorno (vero) o commenti che dovresti usare al loro posto. –

0

Hai l'idea giusta. Troverete spesso che hanno un paio di modalità di funzionamento. Se sei preoccupato che il tuo metodo non venga chiamato o non venga chiamato nell'ordine corretto, spesso c'è una modalità 'strict' che fa sì che il framework mock lanci un'eccezione se il metodo non viene chiamato entro la fine del test, o viene chiamato con i parametri errati ecc.

La maggior parte dei framework ha pensato a questi tipi di problemi, quindi è sufficiente sapere come configurarlo per il proprio scenario.

0

Un modo per vedere come funziona il sistema mock è guardare le volte in cui hai bisogno di un oggetto ma non vuoi usare la classe reale ma preferisci che ti dia qualche tipo specifico di dati che non vorrebbe t (o non lo farà in modo affidabile). Quindi, se vedi:

Assert.IsTrue(myLogic.IsNoon(time)) 

puoi vedere come l'asserzione vorrebbe che l'oggetto orario sia sempre mezzogiorno. . . beh, non puoi farlo con un oggetto reale in modo affidabile. Quindi hai bisogno di un supporto. Puoi fare una lezione finta solo per il test, ma è un po 'pesante. I framework finti sono una scorciatoia.