如何使用moq设置BeginXXX EndXXX方法调用?

时间:2012-06-30 11:14:32

标签: c# wcf asynchronous moq async-await

假设我有一些APM(BeginXxx,EndXxx)模式异步方法(作为我正在调用的一些WCF服务代理的一部分):

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

我的实际代码使用Task.Factory.FromAsync创建一个Task,然后使用.net 4.5中引入的新的async / await模式等待此任务。

我想测试我的类,因此我需要编写一个接收mock,begin方法,end方法和返回值的方法,并设置mock以便最终返回所需的返回值。

示例用法:

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

这会导致异步流与任何int参数返回7。 我似乎无法弄清楚如何在moq中完成这样的事情。

1 个答案:

答案 0 :(得分:6)

首先,我建议您使用TaskWsdlImportExtension创建基于Task的异步WCF代理。 VS2012默认执行此操作,但您在VS2010 + AsyncCTP上have to set it up yourself。对Task API进行单元测试更容易。

如果您确实希望针对Begin / End进行单元测试,我认为最简单的方法是使用基于Task的模拟并公开Begin / {{ 1}}端点。 AsyncEx库中的End方法在[AsyncFactory|AsyncFactory<T>].[ToBegin|ToEnd]周围提供Begin / End方法包装,或者您可以看到Stephen Toub's blog post about writing these kinds of wrappers

您可以从Task获取简单的已完成任务,或者您可以使用以下构造来强制执行异步完成的任务:

Task.FromResult

(异步CTP等价物):

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

我不完全确定如何将其与Moq联系起来。同样,我怀疑基于TaskEx.RunEx(async () => { await TaskEx.Yield(); return 7; }); 的API比Task / Begin更容易模拟。 End / Begin有自己的特殊语义(您必须传递正确的EndIAsyncResult必须为每个End调用一次,等等,所以有更多的东西需要测试。