Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting synchronous Moq mocks to async

Tags:

I am working on converting a body of synchronous asp.net code to .net 4.5 and the new async syntax.

I have a lot of test code that looks like:

var retVal = new Foo(bar,baz); _myMock.Setup(x => x.DoSomething(123)).Returns(retVal); 

When I convert the signature of DoSomething from Foo DoSomething() to async Task<Foo> DoSomething(), all of my test code has to be rewritten. My current workaround is to convert the original code to something like:

var retVal = new Foo(bar,baz); _myMock.Setup(x => x.DoSomething(123))    .Returns(new Task<Foo>(()=>retVal)); 

This is not a particularly hard transform, but it is tedious when I have thousands of tests that need to be updated.

I tried making an extension method called ReturnsAsync to do some of that form m, but I was having some type inferrence issues that I couldn't quite nail down. Is there a standard or easier way to convert this kind of mock to handle the async method better?

like image 916
captncraig Avatar asked Aug 22 '12 21:08

captncraig


1 Answers

First, naming: The Task-based Asynchronous Pattern (TAP) says that all methods that are asynchronous and return Tasks should be named ending with Async. So, your method should be named DoSomethingAsync.

Second, the constructor of Task creates a Task that is not started, you have to Start() it manually. If your actual DoSomething method does this too, that again doesn't follow TAP and it means your code won't work well with await. Instead, you should use Task.Run(() => value), or, even better, Task.FromResult(value).

Third, it would be better if you showed us your code that didn't work well, so that we could tell you where did you make a mistake.

Now, the body of ReturnsAsync() extension method is quite simple, but most of the work for me was in figuring out the correct types (especially since I don't know Moq). The code looks like this:

public static class MoqExtensions {     public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult>(         this IReturns<TMock, Task<TResult>> setup, TResult value)         where TMock : class     {         return setup.Returns(Task.FromResult(value));     } } 
like image 56
svick Avatar answered Sep 27 '22 20:09

svick