2010-07-17 16 views
107

Immaginate questa classeMoq: Come arrivare ad un parametro passato a un metodo di un servizio deriso

public class Foo { 

    private Handler _h; 

    public Foo(Handler h) 
    { 
     _h = h; 
    } 

    public void Bar(int i) 
    { 
     _h.AsyncHandle(CalcOn(i)); 
    } 

    private SomeResponse CalcOn(int i) 
    { 
     ...; 
    } 
} 

Mo (q) cking Handler in una prova di Foo, come vorrei essere in grado di controllare ciò che Bar() è passato a _h.AsyncHandle?

+0

Intendevi "AsyncHandle" (extra "n")? E potresti pubblicare il codice per Handler o specificare il nome di tipo completo se è di tipo standard? – TrueWill

+0

Puoi mostrare il tuo test di scheletro per mostrare cosa stai pensando? Mentre apprezzo che dalla tua parte è ovvio, da parte nostra, sembra qualcuno che non ha avuto il tempo di rispondere alla domanda senza fare una lunga risposta speculativa. –

+1

Non c'è né Foo né Bar() né nulla di simile. È solo un po 'di codice dimostrativo per mostrare la situazione in cui mi trovo senza distrarre dalle specifiche dell'applicativo. E ho ottenuto solo la risposta, speravo di ottenere. – Jan

risposta

178

È possibile utilizzare il metodo di Mock.Callback-:

var mock = new Mock<Handler>(); 
SomeResponse result = null; 
mock.Setup(h => h.AnsyncHandle(It.IsAny<SomeResponse>())) 
    .Callback<SomeResponse>(r => result = r); 

// do your test 
new Foo(mock.Object).Bar(22); 
Assert.NotNull(result); 

Se si vuole solo controllare qualcosa di semplice sul passato in argomento, è anche possibile farlo direttamente:

mock.Setup(h => h.AnsyncHandle(It.Is<SomeResponse>(response => response != null))); 
+1

perfetto, grazie! – Jan

+14

Una nota a margine, se si hanno più argomenti per la propria funzione, è necessario specificare tutti i tipi nel metodo Moq generico 'Richiamata <>()'. Ad esempio, se il metodo avesse la definizione 'Handler.AnsyncHandle (string, SomeResponse)', avresti bisogno di '/ * ... * /. Callback (r => result = r);'. Non ho trovato questo esplicitamente dichiarato in molti posti, quindi ho pensato di aggiungerlo qui. –

17

Gamlor di risposta funziona, ma un altro modo di farlo (e uno che considero più espressivo nel test) è ...

var mock = new Mock<Handler>(); 
var desiredParam = 47; // this is what you want to be passed to AsyncHandle 
new Foo(mock.Object).Bar(22); 
mock.Verify(h => h.AsyncHandle(desiredParam), Times.Once()); 

La verifica è molto potente e vale la pena prendersi il tempo per abituarsi.

+9

Questo approccio va bene se si desidera verificare se un metodo è stato chiamato con un parametro noto. Nel caso in cui il parametro non sia stato ancora creato al momento della scrittura del test (ad esempio, l'unità in questione crea il parametro internamente), quindi Callback consente di catturare e interrogare questo, mentre il tuo approccio non lo farebbe. – Michael

+0

Ho bisogno di memorizzare il valore passato perché devo verificare che tutto il set di oggetti sia passato. – MrFox

1

È possibile utilizzare il Matcher It.Is<TValue>().

var mock = new Mock<Handler>(); new Foo(mock.Object).Bar(22); mock.Verify(h => h.AsyncHandle(It.Is<SomeResponse>(r => r != null)));

+0

Typo - 'AnsyncHandle' dovrebbe essere 'AsyncHandle' –

2

risposta di Gamlor lavorato per me, ma ho pensato di ampliare il commento di John Carpenter, perché ero alla ricerca di una soluzione che comprenda più di un parametro. Ho pensato che le altre persone che si imbattessero in questa pagina potrebbero trovarsi in una situazione simile. Ho trovato queste informazioni nel Moq documentation.

Userò l'esempio di Gamlor, ma supponiamo che il metodo AsyncHandle utilizzi due argomenti: uno string e un oggetto SomeResponse.

var mock = new Mock<Handler>(); 
string stringResult = string.Empty; 
SomeResponse someResponse = null; 
mock.Setup(h => h.AsyncHandle(It.IsAny<string>(), It.IsAny<SomeResponse>())) 
    .Callback<string, SomeResponse>((s, r) => 
    { 
     stringResult = s; 
     someResponse = r; 
    }); 

// do your test 
new Foo(mock.Object).Bar(22); 
Assert.AreEqual("expected string", stringResult); 
Assert.IsNotNull(someResponse); 

Fondamentalmente è solo bisogno di aggiungere un altro It.IsAny<>() con il tipo appropriato, aggiungere un altro tipo al metodo Callback, e cambiare l'espressione lambda a seconda dei casi.

Problemi correlati