Mocked HttpClient包装器使用xunit返回null

时间:2017-04-06 09:32:57

标签: c# .net unit-testing moq xunit

我正在尝试使用.net核心进行单元测试。不幸的是,我坚持让我的HttpClient包装器返回失败的HttpResponseMessage

这是我的测试,我正在努力工作:

[Fact]
public async void TestHttpExceptionOnBadRequest()
{
    using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("Test")))
    {
        var xmlSerializer = new Mock<IXmlSerializer>();
        xmlSerializer.Setup(serializer => serializer.Deserialize(stream)).Returns(new object());

        var httpClient = new Mock<IHttpHandler>();
        httpClient.Setup(client => client.GetAsync("Test"))
            .Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.BadRequest)));

        var postcodeLookup = new PostcodeLookupService(xmlSerializer.Object, httpClient.Object, "", "");
        await Assert.ThrowsAsync<HttpRequestException>(async () => await postcodeLookup.SearchAsync("", ""));
    }
}

以下是我的服务代码。问题是response.EnsureSuccessStatusCode();返回null。

public async Task<PostcodeContainer> SearchAsync(string text, string container)
{
    // add the query parameters to the query string
    var query = _baseQueryString + "&text=" + WebUtility.UrlEncode(text);
    query += "&container=" + WebUtility.UrlEncode(container);

    // initiate client & response
    var response = await _httpClient.GetAsync(query);
    response.EnsureSuccessStatusCode();

    return (PostcodeContainer)_serializer.Deserialize(await response.Content.ReadAsStreamAsync());
}

为了完整性,这里是我的IHttpHandler定义,用于模拟。

public interface IHttpHandler
{
    HttpResponseMessage Get(string url);
    HttpResponseMessage Post(string url, HttpContent content);
    Task<HttpResponseMessage> GetAsync(string url);
    Task<HttpResponseMessage> PostAsync(string url, HttpContent content);
}

1 个答案:

答案 0 :(得分:2)

这是因为预期的查询设置与测试中的方法生成的不匹配。

// add the query parameters to the query string
var query = _baseQueryString + "&text=" + WebUtility.UrlEncode(text);
query += "&container=" + WebUtility.UrlEncode(container);

这会导致模拟返回null,因为它在获得与"Test"不匹配的意外查询时不知道该怎么做。

因此假设_baseQueryString也是基于示例中的测试的空字符串,生成的查询可能最终为

&text=&container=

因此,为了按预期执行,这就是模拟应该期望接收的内容。另外,由于被测试的方法在序列化器执行任何操作之前都会出错,因此无需将其设置为执行任何操作。只是嘲笑并通过模拟。

您还可以让客户端在设置表达式中使用It.IsAny<string>()进行任何查询。

最后,如果执行acync功能,则让测试返回Task

[Fact]
public async Task TestHttpExceptionOnBadRequest() {

    var xmlSerializer = new Mock<IXmlSerializer>();
    xmlSerializer
        .Setup(serializer => serializer.Deserialize(It.IsAny<Stream>()))
        .Returns(new PostcodeContainer());

    var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest);
    var httpClient = new Mock<IHttpHandler>();
    httpClient
        .Setup(client => client.GetAsync(It.IsAny<string>()))
        .ReturnsAsync(expectedResponse);

    var postcodeLookup = new PostcodeLookupService(xmlSerializer.Object, httpClient.Object, "", "");
    await Assert.ThrowsAsync<HttpRequestException>(async () => await postcodeLookup.SearchAsync("", ""));
}