【问题标题】:How to write unit test case IHttpClientFactory如何编写单元测试用例 IHttpClientFactory
【发布时间】:2021-05-07 15:29:15
【问题描述】:

我在服务层有一个连接服务的方法,我正在使用IHttpClientFactory。我的方法工作正常。现在我正在尝试为此编写单元测试用例。

public async Task<MyObject> MyMethodAsync(string arg1, string arg2)
{
    var client = _httpClientFactory.CreateClient("XYZ");

    var Authkey = "abc"; 
    var AuthToken = "def";
       
    var headers = new Dictionary<string, string>
        {
            { Authkey,AuthToken }
        };

    client.AddTokenToHeader(headers); //This method set  the DefaultRequestheader from the dictionary object

    var reqData = new
    {
        prop1 = "X", 
        prop2 = "Y"
    };//req object

    var content = new StringContent(JsonConvert.SerializeObject(reqData), Encoding.UTF8, "application/json");

    //This is httpClient Post call for posting data 
    HttpResponseMessage response = await client.PostAsync("postData", content); 
    if (!response.IsSuccessStatusCode || response.Content == null)
    {
        return null;
    }

    MyObject myObject = JsonConvert.DeserializeObject<MyObject>(response.Content.ReadAsStringAsync().Result);//read the result to an object
    return myObject;
}

对于上述方法,我正在编写测试用例。在这里,我试图将 Post 方法设置为输出状态代码 OK 并期待 MyMethodAsync 方法为真,因为PostAsync 为真。这里我遇到了一个异常

System.InvalidOperationException:提供了无效的请求 URI。请求 URI 必须是绝对 URI,或者必须设置 BaseAddress。

[Test]
public async Task MyMethodAsync_Gets_True()
{
    var response = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new StringContent("It worked!")
    };

    //Mock the httpclientfactory
    var _httpMessageHandler = new Mock<HttpMessageHandler>();
    var mockFactory = new Mock<IHttpClientFactory>(); 

    //Specify here the http method as post
    _httpMessageHandler.Protected()
      .Setup<Task<HttpResponseMessage>>("SendAsync",
       ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Post),
       ItExpr.IsAny<CancellationToken>())
       .ReturnsAsync(new HttpResponseMessage
       {
           StatusCode = HttpStatusCode.OK
       });


    var httpClient = new HttpClient(_httpMessageHandler.Object);
    mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);

    var arg1 = "X";
    var arg2 = "D101";

    var service = new MyService(_mockAppSettings.Object, mockFactory.Object);
    var result = await service.MyMethodAsync(arg1, arg2);
    // Assert
    Assert.IsNotNull(result);
}

有人能说明我在这里犯了什么错误吗?

【问题讨论】:

    标签: c# asp.net asp.net-core httpclientfactory


    【解决方案1】:

    正如例外所说,你必须这样做

    • 使用绝对 URL 调用 PostAsync
    • 或者设置HttpClient的BaseAddress

    如果你选择第二个,你需要做的就是:

    var httpClient = new HttpClient(_httpMessageHandler.Object);
    
    httpClient.BaseAddress = new Uri("http://nonexisting.domain"); //New code
    
    mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);
    

    通过此修改,异常将消失。
    但是您的测试将失败,因为response.Content 将是null,这就是为什么MyMethodAsync 将返回null

    要解决这个问题,让我们将设置更改为:

    public static async Task MyMethodAsync_Gets_True()
    {
        //Arrange
        MyObject resultObject = new MyObject();
        var response = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(JsonConvert.SerializeObject(resultObject))
        };
    
        var _httpMessageHandler = new Mock<HttpMessageHandler>();
        _httpMessageHandler.Protected()
            .Setup<Task<HttpResponseMessage>>("SendAsync",
              ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Post),
              ItExpr.IsAny<CancellationToken>())
            .ReturnsAsync(response);
        ...
    
        //Act
        var result = await service.MyMethodAsync(arg1, arg2);
    
        //Assert
        Assert.NotNull(result);
    }
    

    【讨论】:

    • 我已经修改添加BaseAddress。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    • 1970-01-01
    • 2019-02-22
    相关资源
    最近更新 更多