web-dev-qa-db-fra.com

Comment puis-je dire à Moq de renvoyer une tâche?

J'ai une interface qui déclare

Task DoSomethingAsync();

J'utilise MoqFramework pour mes tests:

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

Ensuite, dans mon test, j'exécute le code qui appelle await DoSomethingAsync(). Et le test échoue simplement sur cette ligne. Qu'est-ce que je fais mal?

272
Waldemar

Votre méthode n'a aucun rappel, il n'y a donc aucune raison d'utiliser .CallBack(). Vous pouvez simplement renvoyer une tâche avec les valeurs souhaitées en utilisant .Returns() et Task.FromResult , par exemple:

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

Mise à jour du 2014-06-22

Moq 4.2 dispose de deux nouvelles méthodes d'extension pour vous aider.

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

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

Mise à jour 2016-05-05

Comme Seth Flowers le mentionne dans le autre réponse , ReturnsAsync n'est disponible que pour les méthodes qui renvoient un Task<T>. Pour les méthodes qui ne renvoient qu'une tâche,

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

peut être utilisé.

Comme indiqué dans cette réponse , dans .NET 4.6, ceci est simplifié en .Returns(Task.CompletedTask);, par exemple:

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

Problème similaire

J'ai une interface qui ressemble à peu près à:

Task DoSomething(int arg);

Symptômes

Mon test unitaire a échoué lorsque mon service en cours de test awaited l'appel à DoSomething.

Fix

Contrairement à la réponse acceptée, vous ne pouvez pas appeler .ReturnsAsync() sur votre Setup() de cette méthode dans ce scénario, car la méthode renvoie le Task non générique, plutôt que Task<T>. .

Cependant, vous pouvez toujours utiliser .Returns(Task.FromResult(default(object))) sur la configuration, permettant ainsi au test de réussir.

37
Seth Flowers

Il vous suffit d'ajouter .Returns(Task.FromResult(0)); après le rappel.

Exemple:

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

Maintenant, vous pouvez également utiliser le package Talentsoft.Moq.SetupAsync https://github.com/TalentSoft/Moq.SetupAsync

Sur la base des réponses trouvées ici et des idées proposées à Moq mais non encore implémentées ici: https://github.com/moq/moq4/issues/384 , simplifie grandement la configuration des méthodes asynchrones

Quelques exemples trouvés dans les réponses précédentes effectuées avec l'extension SetupAsync:

mock.SetupAsync(arg=>arg.DoSomethingAsync());
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Callback(() => { <my code here> });
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Throws(new InvalidOperationException());
3
user9812476