基于服务元数据生成的Moq异步函数

时间:2014-05-14 09:11:07

标签: .net wcf unit-testing asynchronous moq

我有一个使用基于任务的异步功能与WCF服务交互的Web应用程序。当我写一个单元测试时遇到了一个关于模拟异步函数调用的问题。我认为不需要显示不必要的业务逻辑,因为所有这些都只在这些异步调用上失败。我试图用两种方式做到这一点,第一种方式是:

[TestMethod]
public async Task GetAndSentSentinelList_AddedTest()
{
    var mockRemoteClient = new Mock<IRemoteManager>();
    mockRemoteClient.Setup(method => method.GetSentinelListAsync(new GetSentinelListRequest()))
        .Returns(Task.FromResult(new GetSentinelListResponse(new RemoteManager.SentinelItem[4]
        {
            new RemoteManager.Item() {Id = "Identity_Host"},
            new RemoteManager.Item() {Id = "Nose_Host"},
            new RemoteManager.Item() {Id = "Sunny_Host"},
            new RemoteManager.Item() {Id = "Ups_Supsu"}
        })));


    var rep = new Repository(hub)
    {
        Client = mockRemoteClient.Object,
        Sentinels = new List<SentinelItem>()
        {
            new Item() {Id = "Identity_Host"},
            new Item() {Id = "Nose_Host"},
            new Item() {Id = "Sunny_Host"}
        }
    };

    var res = await rep.Client.GetSentinelListAsync(new GetSentinelListRequest());

    //Assert
    Assert.IsNotNull(res );

}

接下来是:

    [TestMethod]
    public async Task GetAndSentSentinelList_AddedTest()
    {
            //Arrange

            var tcs = new TaskCompletionSource<GetSentinelListResponse>();

            var expectedResult = new GetSentinelListResponse(new RemoteManager.SentinelItem[4]
                {
                    new RemoteManager.Item() {Id = "Identity_Host"},
                    new RemoteManager.Item() {Id = "Nose_Host"},
                    new RemoteManager.Item() {Id = "Sunny_Host"},
                    new RemoteManager.Item() {Id = "Ups_Supsu"}
                });

            tcs.SetResult(expectedResult);

            var mockRemoteClient = new Mock<IRemoteManager>();
            mockRemoteClient.Setup(method => method.GetSentinelListAsync(new GetSentinelListRequest()))
                .Returns(tcs.Task);


            var rep = new Repository(hub)
            {
                Client = mockRemoteClient.Object,
                Sentinels = new List<SentinelItem>()
                {
                    new Item() {Id = "Identity_Host"},
                    new Item() {Id = "Nose_Host"},
                    new Item() {Id = "Sunny_Host"}
                }
            };

            var res = await rep.Client.GetSentinelListAsync(new GetSentinelListRequest());

            Assert.IsNotNull();
    }

也许我会添加生成的代码,因为我现在很困惑为什么它不能正常工作,生成抽象接口IRemoteManager:

 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
 [System.ServiceModel.ServiceContractAttribute(ConfigurationName="RemoteManager.IRemoteManager", CallbackContract=typeof(Web_Manager.RemoteManager.IRemoteManagerCallback))]
public interface IRemoteManager 
{
    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IRemoteManager/GetSentinelList", ReplyAction="http://tempuri.org/IRemoteManager/GetSentinelListResponse")]
    System.Threading.Tasks.Task<Web_Manager.RemoteManager.GetSentinelListResponse> GetSentinelListAsync(Web_Manager.RemoteManager.GetSentinelListRequest request);

}

具体生成的IRemoteManager实现, - RemoteManagerClient:

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class RemoteManagerClient : System.ServiceModel.DuplexClientBase<Web_Manager.RemoteManager.IRemoteManager>, Web_Manager.RemoteManager.IRemoteManager {
             [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
    System.Threading.Tasks.Task<Web_Manager.RemoteManager.GetSentinelListResponse> Web_Manager.RemoteManager.IRemoteManager.GetSentinelListAsync(Web_Manager.RemoteManager.GetSentinelListRequest request) {
        return base.Channel.GetSentinelListAsync(request);
    }
}

1 个答案:

答案 0 :(得分:1)

我对Moq并不熟悉,但您可以尝试的一件事是在设置模拟时以及调用它时传递相同的SentinelListRequest

[TestMethod]
public async Task GetAndSentSentinelList_AddedTest()
{
    var sentinelRequest = new GetSentinelListRequest();
    var mockRemoteClient = new Mock<IRemoteManager>();
    mockRemoteClient.Setup(method => method.GetSentinelListAsync(sentinelRequest))
        .Returns(Task.FromResult(new GetSentinelListResponse(new RemoteManager.SentinelItem[4]
        {
            new RemoteManager.Item() {Id = "Identity_Host"},
            new RemoteManager.Item() {Id = "Nose_Host"},
            new RemoteManager.Item() {Id = "Sunny_Host"},
            new RemoteManager.Item() {Id = "Ups_Supsu"}
        })));


    var rep = new Repository(hub)
    {
        Client = mockRemoteClient.Object,
        Sentinels = new List<SentinelItem>()
        {
            new Item() {Id = "Identity_Host"},
            new Item() {Id = "Nose_Host"},
            new Item() {Id = "Sunny_Host"}
        }
    };

    var res = await rep.Client.GetSentinelListAsync(sentinelRequest);

    //Assert
    Assert.IsNotNull(res );
}

另一种选择可能是使用类似this

的内容来指定忽略调用的参数
mockRemoteClient.Setup(method => method.GetSentinelListAsync(It.IsAny<SentinelGetRequest>()))
            .Returns(Task.FromResult(new GetSentinelListResponse(new RemoteManager.SentinelItem[4]
            {
                new RemoteManager.Item() {Id = "Identity_Host"},
                new RemoteManager.Item() {Id = "Nose_Host"},
                new RemoteManager.Item() {Id = "Sunny_Host"},
                new RemoteManager.Item() {Id = "Ups_Supsu"}
            })));