447

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?

Waldemar
  • 5,363
  • 3
  • 17
  • 28
  • 5
    When you say the test errors on that line, what error does it produce? – AlSki Jan 21 '14 at 09:07
  • @AlSki propably a NullReferenceException. as you can see [here](https://stackoverflow.com/questions/53882817/nullreferenceexception-in-unittest-using-verifyable-on-an-async-method) – LuckyLikey Dec 21 '18 at 11:57

5 Answers5

917

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);
Seth Flowers
  • 8,990
  • 2
  • 29
  • 42
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • 29
    .Returns(Task.CompletedTask); that was my answer – Todd Vance Jun 07 '16 at 15:19
  • 12
    Thank you for keeping this answer up-to-date as the Moq framework has received updates! – Jacob Stamm Apr 06 '18 at 18:31
  • `.Returns(Task.FromResult(default(object))` works well when the return type is void. `.Returns(Task.FromResult(null as MyType))` works well when the expected return type is null. – Jeremy Ray Brown Feb 22 '19 at 22:37
  • 1
    @JeremyRayBrown as I explain, in .NET 4.6 `default(object)` is no longer needed. `null as MyType` is the same as `default(MyType)` as long as `MyType` is a reference type. – Panagiotis Kanavos Feb 25 '19 at 08:33
  • now in .net and Mock supports ReturnAsync and directly return your object. without Task.CompletedTask or FromResult – Ahmed Magdy Aug 12 '22 at 02:55
44

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.

Seth Flowers
  • 8,990
  • 2
  • 29
  • 42
  • 1
    Just a thought on this, if you need to return a non-generic task (non .net 4.6), I would consider returning Task.Delay(1) as an easy way to return a Task. You can also mimic work too by increasing the time argument. – stevethethread Apr 18 '16 at 11:10
30

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));
Diego Torres
  • 1,213
  • 12
  • 5
4

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());
0

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();
Patrick McDonald
  • 64,141
  • 14
  • 108
  • 120