Come posso dire a Moq di restituire un'attività?


327

Ho un'interfaccia che dichiara

Task DoSomethingAsync();

Sto usando MoqFramework per i miei test:

[TestMethod()]
public async Task MyAsyncTest()
{
   Mock<ISomeInterface> mock = new Mock<ISomeInterface>();
   mock.Setup(arg => arg.DoSomethingAsync()).Callback(() => { <my code here> });
   ...
}

Quindi nel mio test eseguo il codice che invoca await DoSomethingAsync(). E il test fallisce proprio su quella linea. Che cosa sto facendo di sbagliato?


5
Quando dite gli errori di test su quella riga, quale errore produce?
AlSki,

@AlSki probabilmente una NullReferenceException. come puoi vedere qui
LuckyLikey il

Risposte:


709

Il tuo metodo non ha alcun callback quindi non c'è motivo di usarlo .CallBack(). È possibile semplicemente restituire un'attività con i valori desiderati utilizzando .Returns()e Task.FromResult , ad esempio:

MyType someValue=...;
mock.Setup(arg=>arg.DoSomethingAsync())        
    .Returns(Task.FromResult(someValue));

Aggiornamento 22/06/2014

Moq 4.2 ha due nuovi metodi di estensione per aiutare con questo.

mock.Setup(arg=>arg.DoSomethingAsync())
    .ReturnsAsync(someValue);

mock.Setup(arg=>arg.DoSomethingAsync())        
    .ThrowsAsync(new InvalidOperationException());

Aggiornamento 05/05/2016

Come menziona Seth Flowers nell'altra risposta , ReturnsAsyncè disponibile solo per i metodi che restituiscono a Task<T>. Per i metodi che restituiscono solo un'attività,

.Returns(Task.FromResult(default(object)))

può essere utilizzato.

Come mostrato in questa risposta , in .NET 4.6 questo è semplificato .Returns(Task.CompletedTask);, ad esempio:

mock.Setup(arg=>arg.DoSomethingAsync())        
    .Returns(Task.CompletedTask);

16
.Returns (Task.CompletedTask); quella era la mia risposta
Todd Vance,

8
Grazie per aver aggiornato questa risposta poiché il framework Moq ha ricevuto aggiornamenti!
Jacob Stamm,

.Returns(Task.FromResult(default(object))funziona bene quando il tipo restituito è nullo. .Returns(Task.FromResult(null as MyType))funziona bene quando il tipo di ritorno previsto è null.
Jeremy Ray Brown,

1
@JeremyRayBrown come spiego, in .NET 4.6 default(object)non è più necessario. null as MyTypeè lo stesso default(MyType)fintanto che MyTypeè un tipo di riferimento.
Panagiotis Kanavos,

40

Problema simile

Ho un'interfaccia che assomigliava più o meno a:

Task DoSomething(int arg);

Sintomi

Il test dell'unità non è riuscito quando il servizio in corso ha verificato awaitedla chiamata a DoSomething.

fix

A differenza della risposta accettata, in questo scenario non è possibile ricorrere .ReturnsAsync()a Setup()questo metodo, poiché il metodo restituisce il non generico Task, anziché Task<T>.

Tuttavia, è ancora possibile utilizzare .Returns(Task.FromResult(default(object)))l'installazione, consentendo il superamento del test.


1
Solo un pensiero su questo, se è necessario restituire un'attività non generica (non .net 4.6), prenderei in considerazione la restituzione di Task.Delay (1) come un modo semplice per restituire un'attività. Puoi anche imitare il lavoro aumentando l'argomento time.
Stevethethread

26

Devi solo aggiungere .Returns(Task.FromResult(0));dopo il callback.

Esempio:

mock.Setup(arg => arg.DoSomethingAsync())
    .Callback(() => { <my code here> })
    .Returns(Task.FromResult(0));

4

Ora puoi anche usare il pacchetto Talentsoft.Moq.SetupAsync https://github.com/TalentSoft/Moq.SetupAsync

Quale sulla base delle risposte trovate qui e idee proposte a Moq ma non ancora implementate qui: https://github.com/moq/moq4/issues/384 , semplifica notevolmente la configurazione dei metodi asincroni

Alcuni esempi trovati nelle risposte precedenti fatte con l'estensione SetupAsync:

mock.SetupAsync(arg=>arg.DoSomethingAsync());
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Callback(() => { <my code here> });
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Throws(new InvalidOperationException());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.