c# – 使用Moq模拟异步方法进行单元测试

我正在测试一个服务的方法,使一个Web API调用。如果我还在本地运行Web服务(位于解决方案中的另一个项目中),使用正常的HttpClient可以很好地进行单元测试。

但是,当我检查我的更改,构建服务器将无法访问Web服务,所以测试将失败。

我已经通过创建一个IHttpClient接口并实现我在我的应用程序中使用的版本,为我的单元测试设计了一个方法。对于单元测试,我做一个嘲笑版本完成与嘲笑异步后方法。这里是我遇到的问题。我想返回一个OK HttpStatusResult为这个特定的测试。对于另一个类似的测试,我将返回一个坏的结果。

测试将运行,但永远不会完成。它挂在等待。我是新的异步编程,代理和Moq本身,我一直在搜索SO和谷歌一段时间学习新的东西,但我仍然不能似乎回避这个问题。

这里是我想测试的方法:

public async Task<bool> QueueNotificationAsync(IHttpClient client, Email email)
{
    // do stuff
    try
    {
        // The test hangs here, never returning
        HttpResponseMessage response = await client.PostAsync(uri, content);

        // more logic here
    }
    // more stuff
}

这里是我的单元测试方法:

[TestMethod]
public async Task QueueNotificationAsync_Completes_With_ValidEmail()
{
    Email email = new Email()
    {
        FromAddress = "bob@example.com",
        ToAddress = "bill@example.com",
        CCAddress = "brian@example.com",
        BCCAddress = "ben@example.com",
        Subject = "Hello",
        Body = "Hello World."
    };
    var mockClient = new Mock<IHttpClient>();
    mockClient.Setup(c => c.PostAsync(
        It.IsAny<Uri>(),
        It.IsAny<HttpContent>()
        )).Returns(() => new Task<HttpResponseMessage>(() => new HttpResponseMessage(System.Net.HttpStatusCode.OK)));

    bool result = await _notificationRequestService.QueueNotificationAsync(mockClient.Object, email);

    Assert.IsTrue(result, "Queue failed.");
}

我究竟做错了什么?

感谢您的帮助。

最佳答案
您正在创建一个任务,但从不启动它,所以它永远不会完成。但是,不要只是启动任务 – 相反,改为使用Task.FromResult<TResult>,这将给你一个已经完成的任务:

...
.Returns(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK)));

注意,你不会这样测试实际的异步 – 如果你想这样做,你需要做一些工作来创建一个任务< T>你可以以更细粒度的方式控制…但这是另一天的东西。

你可能还想考虑使用一个假的IHttpClient,而不是嘲笑一切 – 这真的取决于你需要多久。

转载注明原文:c# – 使用Moq模拟异步方法进行单元测试 - 代码日志