2014-05-01 64 views
24

Sto configurando alcuni test unitari e utilizzo di Rhino Mocks per popolare l'oggetto da testare. Una delle cose che viene derisa è una Task<HttpResponseMessage>, dal momento che la logica da testare include una chiamata a un HttpClient per ottenere una risposta asincrona.Come simulare un'attività <> Risultato?

Così ho iniziato a impostare i mock come questo:

var httpClient = MockRepository.GenerateMock<HttpClient>(); 
var taskFunc = MockRepository.GenerateMock<Func<HttpResponseMessage>>(); 
var responseTask = MockRepository.GenerateMock<Task<HttpResponseMessage>>(taskFunc); 
var response = MockRepository.GenerateMock<HttpResponseMessage>(); 

httpClient.Stub(c => c.PostAsJsonAsync<IEnumerable<LogMessage>>(Arg<string>.Is.Anything, Arg<IEnumerable<LogMessage>>.Is.Anything)).Return(responseTask); 
responseTask.Stub(t => t.Result).Return(response); 
response.Stub(r => r.IsSuccessStatusCode).Return(true); 

(la "Legge" fase del test sarà quello di creare un'istanza dell'oggetto in fase di test, a passare i httpClient, ed eseguire un metodo . su di esso il "affermare" verificherà attraverso i mock che prevede chiamate di metodo sono state fatte su di loro)

Facendo un passo attraverso questo in un debugger, c'è un indefinito appendere su questa linea:.

responseTask.Stub(t => t.Result).Return(response); 

Non ho molta esperienza con Rhino Mocks o con C# async, quindi potrei trascurare qualcosa di ovvio. L'obiettivo, ovviamente, è che qualsiasi chiamata alla proprietà .Result restituirebbe la simulazione response. Ma sembra che il mio tentativo stia forse invocando .Result che mi aspetterei di aspettare indefinitamente dal momento che è solo un finto, forse?

Qual è il modo giusto per organizzare questo? Essenzialmente ho bisogno di fornire il mio oggetto con un HttpClient deriso e asserire che un metodo è stato chiamato su di esso con un argomento specifico.

+1

Ho fatto un sacco di beffe di Google circa un anno fa usando MOQ. A meno che non mi sbagli, devi solo sostituire il taskFunc che stai passando nel tuo simulato responseTask. Quindi la funzione fittizia restituisce immediatamente una risposta. – Keith

+0

@ Keith: interessante. Quindi basta creare un vero 'Func ' invece di un mock, che restituisce solo? Ho appena provato come tale: 'Func taskFunc = delegate() {return response; }; 'e passa' taskFunc' al simulatore 'responseTask', ma si osserva lo stesso comportamento. – David

+1

Non penso che sia necessario un compito fittizio. Quello che ti serve è la funzione che viene passata nell'attività, quindi restituirà semplicemente "x". – Keith

risposta

37

La cosa più semplice è solo quello di restituire un'attività completata con il risultato atteso:

var responseTask = Task.FromResult(response); 

immagino ragione per cui questo si blocca è che il compito deriso non è mai iniziato e quindi la data func non viene eseguito. Si potrebbe iniziare nel tuo test:

var responseTask = MockRepository.GenerateMock<Task<HttpResponseMessage>>(taskFunc); 
responseTask.Start(); 

Tuttavia non c'è alcun motivo per deridere le attività dal momento che è possibile creare facilmente completato/fallito/annullata attività direttamente.

+0

Sembra che stia facendo il trucco. Con questo ho anche bisogno di rimuovere da queste ultime due chiamate 'Stub()'. ('.Result' è gestito dalla tua risposta,' .IsSuccessStatusCode' stava generando un errore quando si tenta di stublo ma sembra comunque predefinito 'true' nel simulato in ogni caso.) Grazie! – David

+0

Grazie, anche questo mi ha aiutato! – Aaron

Problemi correlati