Coder Perfect

What is the best way to get Moq to return a Task?

Problem

I’ve got an interface which declares

Task DoSomethingAsync();

For my experiments, I’m using MoqFramework:

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

Then I run the code that calls await DoSomethingAsync in my test (). And that line is where the test fails. What am I doing incorrectly?

Asked by Waldemar

Solution #1

There’s no reason to use because your method doesn’t contain any callbacks. CallBack(). Using the method, you can simply return a Task with the necessary values. Returns() and Task are two functions that can be used together. For example, consider the following:

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

Update 2014-06-22

To help with this, Moq 4.2 provides two new extension methods.

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

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

Update 2016-05-05

ReturnsAsync is only available for methods that return a TaskT>, as Seth Flowers points out in the other answer. Only a Task is returned by methods that return only a Task.

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

can be used.

In.NET 4.6, as indicated in this response, this is simplified to.Returns(Task.CompletedTask);, for example:

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

Answered by Panagiotis Kanavos

Solution #2

Similar Issue

I had a user interface that looked somewhat like this:

Task DoSomething(int arg);

Symptoms

When my service under test awaited the call to DoSomething, my unit test failed.

Fix

You are unable to call, contrary to popular belief. In this case, you should use ReturnsAsync() on the Setup() of this method because it returns a non-generic Task rather than TaskT>.

You can, however, continue to utilize. On the setup, returns(Task.FromResult(default(object)) allowing the test to pass.

Answered by Seth Flowers

Solution #3

All you have to do now is add. After the Callback, returns(Task.FromResult(0)).

Example:

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

Answered by Diego Torres

Solution #4

You can now use Talentsoft as well. https://github.com/TalentSoft/Moq.SetupAsync/wiki/Moq.SetupAsync/wiki/Moq.SetupAsync/wiki/Moq.SetupAsync/wiki/Moq.SetupA

Which of the following, based on the responses collected here and ideas given to Moq but not yet implemented: https://github.com/moq/moq4/issues/384 makes setting up async methods a breeze.

Following are a few examples from earlier SetupAsync responses:

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

Answered by user9812476

Post is based on https://stackoverflow.com/questions/21253523/how-can-i-tell-moq-to-return-a-task