rony l
rony l

Reputation: 6022

How to setup a BeginXXX EndXXX method call with moq?

Let's say I have some APM (BeginXxx, EndXxx) pattern async methods (as part of some WCF service proxy i'm calling):

public interface ISomeService
{
    IAsyncResult BeginSomeMethod(int num, AsyncCallback callback, object state);
    int EndSomeMethod(IAsyncResult ar);
}

My actual code uses uses the Task.Factory.FromAsync to create a Task, and then awaiting this task using the new async/await pattern introduced in .net 4.5.

I would like to test my class and thus I need to write a method that receives the mock, begin method, end method and return value and sets up the mock so that it would eventually return the required return value.

example usage:

SetupAsync(mock, mocked => mocked.BeginSomeMethod, mocked=> mocked.EndSomeMethod, 7);

Which will cause an async flow with any int argument to return 7. I cannot seem to figure out how to accomplish such a thing in moq.

Upvotes: 6

Views: 1692

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456717

First, I recommend that you use the TaskWsdlImportExtension to create Task-based asynchronous WCF proxies. VS2012 does this by default, but you have to set it up yourself on VS2010+AsyncCTP. It's easier to unit test against a Task API.

If you do want to unit test against Begin/End, I think the easiest way would be to use Task-based mocks and expose Begin/End endpoints. The [AsyncFactory|AsyncFactory<T>].[ToBegin|ToEnd] methods in my AsyncEx library provide Begin/End method wrappers around a Task, or you can see Stephen Toub's blog post about writing these kinds of wrappers.

You can get simple already-completed tasks from Task.FromResult, or you can use the following construct to force an asynchronously-completed task:

Task.Run(async () => { await Task.Yield(); return 7; });

(the Async CTP equivalent would be):

TaskEx.RunEx(async () => { await TaskEx.Yield(); return 7; });

I'm not entirely sure how to tie this into Moq. Again, I suspect a Task-based API would be easier to mock than Begin/End. Begin/End has its own special semantics (you have to pass the correct IAsyncResult, End must be called exactly once for each Begin, etc), so there's more stuff to test.

Upvotes: 6

Related Questions