Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpClient mock

.NET 7, xUnit, moq

I get an error while testing this:

// Arrange
var mockHttpClientFactory = new Mock<IHttpClientFactory>();
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
var expectedResponseContent = "response content";

mockHttpMessageHandler.Protected()
    .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
    .ReturnsAsync(new HttpResponseMessage
    {
        StatusCode = HttpStatusCode.OK,
        Content = new StringContent(expectedResponseContent)
    });

var httpClient = new HttpClientAdapter(mockHttpMessageHandler.Object)
{
    BaseAddress = new("https://stackoverflow.com")
};

mockHttpClientFactory.Setup(_ => _.CreateClient("someClient"))
    .Returns(httpClient);

var controller = new SomeController(mockHttpClientFactory.Object);

// Act
var result = await controller.GetPayloadAsync();

// Assert
Assert.Equal(expectedResponseContent, result);

Error:

System.Net.Http.HttpRequestException : Error while copying content to a stream.

System.ObjectDisposedException : Cannot access a closed Stream.

Code I'm testing:

await client.GetStringAsync("https://stackoverflow.com")

In the test I started off just mocking HttpClient with HttpClientFactory but that showed the error. I then implemented this.

but I still get the same error. Modified it like this:

class HttpClientAdapter : HttpClient, IClient
{
    public HttpClientAdapter(HttpMessageHandler httpMessageHandler): base(httpMessageHandler)
    {
    }

    public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default) => base.SendAsync(request, cancellationToken);
}

Any ideas how to test this without the stream being closed?

like image 567
Jason Foglia Avatar asked Jan 17 '26 19:01

Jason Foglia


1 Answers

What I did to fix the issue that @jdweng in the comments explained. I needed to rewrite the Setup of SendAsync for 2 Http calls. Here is the code.

var handlerIndex = 0;

mockHttpMessageHandler.Protected()
    .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
    .ReturnsAsync(() =>
    {
        if (handlerIndex == 0)
        {
            handlerIndex++; // Increment the index for the second call
            return new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.OK,
                Content = new StringContent(expectedResponseContent1)
            };
        }
        else
        {
            return new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.OK,
                Content = new StringContent(expectedResponseContent2)
            };
        }
    })
    .Verifiable();
like image 180
Jason Foglia Avatar answered Jan 19 '26 19:01

Jason Foglia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!