Reputation: 5513
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?
Upvotes: 460
Views: 269971
Reputation: 65421
Thanks to the accepted answer for a very helpful solution.
I have added two extension methods (for Task
and ValueTask
) to our projects to make it more discoverable for people used to calling .ReturnsAsync
on all async setups.
public static class MoqExtensions
{
public static IReturnsResult<TMock> ReturnsAsync<TMock>(this IReturns<TMock, Task> mock)
where TMock : class
{
return mock.Returns(Task.CompletedTask);
}
public static IReturnsResult<TMock> ReturnsAsync<TMock>(this IReturns<TMock, ValueTask> mock)
where TMock : class
{
return mock.Returns(ValueTask.CompletedTask);
}
}
It can be called as follows:
mock.Setup(x => x.DoSomethingAsync())
.ReturnsAsync();
Upvotes: 0
Reputation: 74
Now you can also use Talentsoft.Moq.SetupAsync package https://github.com/TalentSoft/Moq.SetupAsync
Which on the base on the answers found here and ideas proposed to Moq but still not yet implemented here: https://github.com/moq/moq4/issues/384, greatly simplify setup of async methods
Few examples found in previous responses done with SetupAsync extension:
mock.SetupAsync(arg=>arg.DoSomethingAsync());
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Callback(() => { <my code here> });
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Throws(new InvalidOperationException());
Upvotes: 4
Reputation: 131189
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);
Upvotes: 946
Reputation: 1223
You only need to add .Returns(Task.FromResult(0));
after the Callback.
Example:
mock.Setup(arg => arg.DoSomethingAsync())
.Callback(() => { <my code here> })
.Returns(Task.FromResult(0));
Upvotes: 30
Reputation: 9190
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.
Upvotes: 45