Mocking (stubbing) async calls (async/await)

.Net 4.5 came out with a really handy built-in asynchronous mechanism, async and await. However the method signature of a void method is a bit strange:

  1. public async Task SomeAction(){...}
  2.  

It is possible to use async void but it's not recommended unless we are talking about event handlers. It's also a bit strange the fact that the type specified in the signature is not the one returned:

  1. public async Task<string> SomeQuery(){
  2. .....
  3. return someString;
  4. }
  5.  

But everything else is great and very handy.

Stubbing method calls can be hard though. You can get weird exceptions like System.AggregateException when running tests with NUnit. The problem comes up when awaiting for a

stubbed async method:

  1. // notice that async tests with NUnit require the method to be async Task rather than void
  2.  
  3. [Test] public async Task
  4. filter_results_from_search(){
  5. var srv = new Mock<Service>(); // using Moq
  6. sut = new Sut(srv.Object);
  7.  
  8. sut.someAction(); // Exception happens here
  9.  
  10. SomeAssertionOverHere();
  11. }
  12. // Production code
  13. public class Service(){ // dependency
  14. public virtual async Task<string> SomeQuery(){ // virtual is mandatory in order to mock it
  15. return "someResult";
  16. }
  17. }
  18. public class Sut(){ // system under test
  19. Service srv;
  20. public Sut(Service srv){
  21. this.srv = srv;
  22. }
  23. public async Task SomeAction(){
  24. var result = await srv.SomeQuery(); // NullReferenceException in here
  25. ....
  26. }
  27. }
  28.  

The problem is that Moq will make the stubbed method return null when invoked, because we are not specifying any return value. The default value for Task<string> is null. We should tell Moq to return a proper Task:

  1. [Test] public async Task
  2. filter_results_from_search(){
  3. var srv = new Mock<Service>();
  4. srv.Setup(s => s
  5. .SomeQuery())
  6. .Returns(Task.Factory.StartNew(
  7. () => "someQuery")
  8. );
  9. sut = new Sut(srv.Object);
  10.  
  11. sut.someAction();
  12.  
  13. SomeAssertionOverHere();
  14. }

The key is to return a new task: Task.Factory.StartNew(lambda)
 

Enjoyed reading this post?
Subscribe to the RSS feed and have all new posts delivered straight to you.
  • http://www.carlosble.com/ Carlos Ble

    Moq 4.2 already provides support for that. I don’t know why my current config using Nuget takes Moq 3.1

  • Dominic Hartjes

    I spent a couple hours trying to figure this out. Thanks Google, and thanks you!