简体   繁体   中英

Net 5 unit test with multiple using httpClientFactory

this is a problem that I have only when trying to write a test. In a Net 5 solution, I test GetResult() in MyController:


public class MyController : ControllerBase
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly IConfiguration _config;

    public MyController(IHttpClientFactory httpClientFactory, IConfiguration config)
    {
        _httpClientFactory = httpClientFactory;
        _config = config;
    }

    public async Task<IActionResult> GetResult(int id)
    {
        var firstResult = await GetFirstResult(id);
        var secondResult = await GetSecondResult(id);

        return Ok("")
    }

    private async Task<int> GetFirstResult(int id)
    {
        using (var httpClient = _httpClientFactory.CreateClient("MySetting"))
        {
            var response = await httpClient.GetAsync($"MyUrl1{id}");
            return (response.IsSuccessStatusCode ? 0 : 1);
        }
    }

    private async Task<int> GetSecondResult(int id)
    {
        using (var httpClient = _httpClientFactory.CreateClient("MySetting"))
        {
            var response = await httpClient.GetAsync($"MyUrl2{id}");
            return (response.IsSuccessStatusCode ? 0 : 1);
        }
    }

My test:

    [Test]
    public async Task Get_Should_Return_OK_String()
    {
        var httpClientFactory = new Mock<IHttpClientFactory>();
        
        var client = new HttpClient();
        client.BaseAddress = new Uri("https://sthing/server.php");
            httpClientFactory.Setup(_ => _.CreateClient(It.IsAny<string>))).Returns(client);

        var config = InitConfiguration();
        
        var controller = new MyController(httpClientFactory.Object, config);
        var result = await controller.GetResult(1);

        Assert.NotNull(result);
    }

An exception is thrown in GetSecondResult() at the line of return(response...). Message: "Cannot access a disposed object. Object name: 'System.Net.Http.HttpClient'."

I am aware of this case Why is this HttpClient usage giving me an "Cannot access a disposed object." error? but there is no use of httpClientFactory. Is there a way to pass false to the constructor of the client through the factory? Why would it work out of the test anyway?

First of all, .NET 5 goes out of support today . You should migrate to .NET 6, the current Long-Term-Support version. This isn't a sudden change, .NET Core's lifecycle was announced several years ago. For the most part, all you need to do is change.net5.0 to.net6.0 in your projects and update NuGet packages.

As for the error, it's caused by the using block:

using (var httpClient = _httpClientFactory.CreateClient("MySetting"))

This isn't needed (it's actually discouraged ), HttpClient instances and sockets are pooled and recycled by the HttpClientFactory.

The test code is configured to return the same HttpClient instance every time:

 var client = new HttpClient();
 client.BaseAddress = new Uri("https://sthing/server.php");
 httpClientFactory.Setup(_ => _.CreateClient(It.IsAny<string>)))
                  .Returns(client);

The call to GetFirstResult() disposes this instance and any subsequent use throws

To fix this just don't use using . HttpClient is meant to be reused anyway:

var httpClient = _httpClientFactory.CreateClient("MySetting");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM