网络核心单元测试中的http类型客户端

时间:2019-06-10 13:18:11

标签: asp.net-core

我将如何进行单元测试,以服务到键入HTTP的客户端的电话? release notes给出的示例未使用界面。

public GitHubService(HttpClient client)

使用xunit / moq进行单元测试是否需要为类型化的客户端创建接口?还是我不需要对该服务进行单元测试。

2 个答案:

答案 0 :(得分:1)

我不明白你的意思

  

http类型的客户端

但是,如果像示例中一样,您想测试使用HttpClient的类,则可以为HttpClient创建一个包装器,并使用依赖注入(使其可以模拟)传递其接口,或者利用 HttpResponseMessage HttpClient的构造函数参数。

使HttpClient成为构造函数参数,并在测试中创建如下代码:

var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
mockHttpMessageHandler.Protected()
   .Setup<Task<HttpResponseMessage>>(
      "SendAsync",
      ItExpr.IsAny<HttpRequestMessage>(), // Customise this as you want
      ItExpr.IsAny<CancellationToken>()
   )
   // Create the response you want to return
   .ReturnsAsync(new HttpResponseMessage()
   {    
      StatusCode = HttpStatusCode.OK,
      Content = new StringContent("[{'prop1': 100,'prop2': 'value'}]"),
   });

// Create an HttpClient using the mocked message handler
var httpClient = new HttpClient(mockHttpMessageHandler.Object)
{
   BaseAddress = new Uri("http://anyurl.com/"),
};

var testedService = new MyServiceUnderTest(httpClient);

var result = await testedService.MethodUnderTest(parameters [...]);

为了简化moq的设置,限制预期的HttpRequestMessage,我使用了此辅助方法。

    /// <summary>
    /// Setup the mocked http handler with the specified criteria
    /// </summary>
    /// <param name="httpStatusCode">Desired status code returned in the response</param>
    /// <param name="jsonResponse">Desired Json response</param>
    /// <param name="httpMethod">Post, Get, Put ...</param>
    /// <param name="uriSelector">Function used to filter the uri for which the setup must be applied</param>
    /// <param name="bodySelector">Function used to filter the body of the requests for which the setup must be applied</param>
    private void SetupHttpMock(HttpStatusCode httpStatusCode, string jsonResponse, HttpMethod httpMethod, Func<string, bool> uriSelector, Func<string, bool> bodySelector = null)
    {
        if (uriSelector == null) uriSelector = (s) => true;
        if (bodySelector == null) bodySelector = (s) => true;

        _messageHandlerMock
            .Protected()
            .Setup<Task<HttpResponseMessage>>("SendAsync",
                ItExpr.Is<HttpRequestMessage>(m =>
                    m.Method == httpMethod &&
                    bodySelector(m.Content.ReadAsStringAsync().Result) &&
                    uriSelector(m.RequestUri.ToString())),
                ItExpr.IsAny<CancellationToken>())
            .ReturnsAsync(new HttpResponseMessage
            {
                StatusCode = httpStatusCode,
                Content = jsonResponse == null ? null : new StringContent(jsonResponse, Encoding.UTF8, "application/json")
            });
    }

答案 1 :(得分:1)

如果服务类的设计适当,则单元测试就没有多大意义。您的方法几乎应该只是封装对HttpClient的调用,提取URL /标题/连接详细信息/等。从一般意义上讲,您可以合理地确定HttpClient可以正常工作,因此实际上没有要测试的代码。再次,这是假设您在做正确的事。

如果您确实需要更复杂的逻辑,则应该有一个将此简单服务类作为依赖项的类,并且复杂的逻辑也应该放在那里。您的服务类 可以实现一个接口,因此您最好在此时进行操作。

您当然可以在您的服务类上进行集成测试,以确保其正常运行,并实际调用API或传真。