Mocking HttpMessageHandler with moq – How do I get the contents of the request?

Is there a way to get the contents of the http request before deciding what kind of response I want to send back for the test? Multiple tests will use this class and each test will have multiple http requests. This code does not compile because the lambda is not async and there is an await in it. I’m new to async-await, so I’m not sure how to resolve this. I briefly considered having multiple TestHttpClientFactories, but that would mean duplicated code, so decided against it, if possible. Any help is appreciated.

public class TestHttpClientFactory : IHttpClientFactory
{
    public HttpClient CreateClient(string name)
    {
        var messageHandlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);

        messageHandlerMock.Protected()
            .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
            .ReturnsAsync((HttpRequestMessage request, CancellationToken token) =>
            {
                HttpResponseMessage response = new HttpResponseMessage();
                var requestMessageContent = await request.Content.ReadAsStringAsync();

                // decide what to put in the response after looking at the contents of the request

                return response;
            })
            .Verifiable();

        var httpClient = new HttpClient(messageHandlerMock.Object);
        return httpClient;
    }
}

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

To take advantage of the async delegate use the Returns method instead

public class TestHttpClientFactory : IHttpClientFactory {
    public HttpClient CreateClient(string name) {
        var messageHandlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);

        messageHandlerMock.Protected()
            .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
            .Returns(async (HttpRequestMessage request, CancellationToken token) => {
                
                string requestMessageContent = await request.Content.ReadAsStringAsync();

                HttpResponseMessage response = new HttpResponseMessage();

                //...decide what to put in the response after looking at the contents of the request

                return response;
            })
            .Verifiable();

        var httpClient = new HttpClient(messageHandlerMock.Object);
        return httpClient;
    }
}

Or consider creating your own handler that exposes a delegate to handle the desired behavior.

For example

public class DelegatingHandlerStub : DelegatingHandler {
    private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
    public DelegatingHandlerStub() {
        _handlerFunc = (request, cancellationToken) => Task.FromResult(request.CreateResponse(HttpStatusCode.OK));
    }

    public DelegatingHandlerStub(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> handlerFunc) {
        _handlerFunc = handlerFunc;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
        return _handlerFunc(request, cancellationToken);
    }
}

And used in the factory like this

public class TestHttpClientFactory : IHttpClientFactory {
    public HttpClient CreateClient(string name) {
        var messageHandlerMock = new DelegatingHandlerStub(async (HttpRequestMessage request, CancellationToken token) => {
                
            string requestMessageContent = await request.Content.ReadAsStringAsync();

            HttpResponseMessage response = new HttpResponseMessage();

            //...decide what to put in the response after looking at the contents of the request

            return response;
        });

        var httpClient = new HttpClient(messageHandlerMock);
        return httpClient;
    }
}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x