关于单元测试:模拟通用WCF ClientChannelWrapper异步调用

Mocking generic WCF ClientChannelWrapper async calls

我最近开发了一个Silverlight应用程序,该应用程序使用Mark J Millers ClientChannelWrapper<T>与WCF服务层进行通信(有效地终止了服务引用并package了IClientChannelClientChannelFactory)。
这是接口:

1
2
3
4
5
6
7
public interface IClientChannelWrapper< T > where T : class
{
    IAsyncResult BeginInvoke(Func<T, IAsyncResult> function);
    void Dispose();
    void EndInvoke(Action< T > action);
    TResult EndInvoke<TResult>(Func<T, TResult> function);
}

package器基本上采用通用的异步服务接口(可能由slsvcutil生成或在WCF ServiceContract之后手工制作),并package调用以确保在出现通道故障的情况下创建新通道。
典型用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 public WelcomeViewModel(IClientChannelWrapper<IMyWCFAsyncService> service)
    {
        this.service = service;
        this.synchronizationContext = SynchronizationContext.Current ?? new SynchronizationContext();
        this.isBusy = true;
        this.service.BeginInvoke(m => m.BeginGetCurrentUser(new AsyncCallback(EndGetCurrentUser), null));
    }

private void EndGetCurrentUser(IAsyncResult result)
    {
        string strResult ="";
        service.EndInvoke(m => strResult = m.EndGetCurrentUser(result));
        this.synchronizationContext.Send(
                    s =>
                    {
                        this.CurrentUserName = strResult;
                        this.isBusy = false;
                    }, null);
    }

一切正常,但是现在我想对使用ClientChannelWrapper的视图模型进行单元测试。
我已经使用Moq建立了一个简单的单元测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
[TestMethod]
    public void WhenCreated_ThenRequestUserName()
    {
        var serviceMock = new Mock<IClientChannelWrapper<IMyWCFAsyncService>>();
        var requested = false;

        //the following throws an exception
        serviceMock.Setup(svc => svc.BeginInvoke(p => p.BeginGetCurrentUser(It.IsAny<AsyncCallback>(), null))).Callback(() => requested = true);


        var viewModel = new ViewModels.WelcomeViewModel(serviceMock.Object);
        Assert.IsTrue(requested);
    }

我收到NotSupportedException:

Unsupported expression: p => p.BeginGetCurrentUser(IsAny(), null).

我对Moq还是很陌生,但是我猜想ClientChannelWrapper使用通用Service接口存在一些问题。现在试图将我的头缠住很长时间,也许有人有一个主意。谢谢。


很抱歉回答我自己的问题,但我终于明白了。
详细信息如下:

通常,该解决方案就在我眼前,因为它在Mark J Millers的IClientChannelWrapper具体实现中。在其中,他提供了两个构造函数,一个构造函数接受一串WCF端点名称(我在生产代码中使用了该字符串),第二个构造函数:

1
2
3
4
public ClientChannelWrapper(T service)
    {
        m_Service = service;
    }

事不宜迟,这是我的新测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
[TestMethod]
    public void WhenCreated_ThenRequestUserName()
    {
        var IMySvcMock = new Mock<IMyWCFAsyncService>();
        var serviceMock = new ClientChannelWrapper<IMyWCFAsyncService>(IMySvcMock.Object);
        var requested = false;

        IMySvcMock.Setup(svc => svc.BeginGetCurrentUser(It.IsAny<AsyncCallback>(), null)).Callback(() => requested = true);
        var viewModel = new ViewModels.WelcomeViewModel(serviceMock);

        Assert.IsTrue(requested);
    }

因此,我基本上忽略了ChannelWrapper的接口,并使用WCF服务接口的Mock Object创建了该接口的新实例。然后,我将设置对服务的调用,该服务将在我的视图模型的构造函数中使用,如上所示。一切现在都像魅力一样。我希望这对某人有用,因为我认为ClientChannelWrapper的想法非常适合Silverlight <-> WCF通信。请随时对此解决方案发表评论!