Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I tell Moq to return a Task?

I've got an interface which declares

Task DoSomethingAsync(); 

I'm using MoqFramework for my tests:

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

Then in my test I execute the code which invokes await DoSomethingAsync(). And the test just fails on that line. What am I doing wrong?

like image 562
Waldemar Avatar asked Jan 21 '14 09:01

Waldemar


People also ask

Can we use return in task?

Whatever you return from async methods are wrapped in a Task . If you return no value(void) it will be wrapped in Task , If you return int it will be wrapped in Task<int> and so on.

How do I return a task in C#?

The recommended return type of an asynchronous method in C# is Task. You should return Task<T> if you would like to write an asynchronous method that returns a value. If you would like to write an event handler, you can return void instead. Until C# 7.0 an asynchronous method could return Task, Task<T>, or void.

How to Mock async function in c#?

First, we instantiate the FakeDbArticleMock class and indicate which setup we want to use for this test. Then, it is necessary to instantiate the repository we want to test and inject the mock instance into it. Finally, we call the method we are testing and assert the results.


2 Answers

Your method doesn't have any callbacks so there is no reason to use .CallBack(). You can simply return a Task with the desired values using .Returns() and Task.FromResult, e.g.:

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

Update 2014-06-22

Moq 4.2 has two new extension methods to assist with this.

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

Update 2016-05-05

As Seth Flowers mentions in the other answer, ReturnsAsync is only available for methods that return a Task<T>. For methods that return only a Task,

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

can be used.

As shown in this answer, in .NET 4.6 this is simplified to .Returns(Task.CompletedTask);, e.g.:

mock.Setup(arg=>arg.DoSomethingAsync())             .Returns(Task.CompletedTask); 
like image 146
Panagiotis Kanavos Avatar answered Oct 22 '22 07:10

Panagiotis Kanavos


Similar Issue

I have an interface that looked roughly like:

Task DoSomething(int arg); 

Symptoms

My unit test failed when my service under test awaited the call to DoSomething.

Fix

Unlike the accepted answer, you are unable to call .ReturnsAsync() on your Setup() of this method in this scenario, because the method returns the non-generic Task, rather than Task<T>.

However, you are still able to use .Returns(Task.FromResult(default(object))) on the setup, allowing the test to pass.

like image 32
Seth Flowers Avatar answered Oct 22 '22 06:10

Seth Flowers