使用Moq模拟HttpMessageHandler - 如何获取请求内容?

9

有没有一种方法可以在决定要发送什么样的响应以进行测试之前获取http请求的内容? 多个测试将使用此类,并且每个测试将具有多个http请求。

此代码无法编译,因为lambda不是async,但其中有一个await。我对async-await不熟悉,所以不知道如何解决这个问题。我曾经考虑过使用多个TestHttpClientFactories,但那意味着重复的代码,因此放弃了,如果可能的话。

任何帮助都将不胜感激。

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;
    }
}

创建自己的处理程序,公开一个委托以处理所需的行为。 - Nkosi
Nkosi,这是个好主意。如果moq行不通,我一定会考虑的。 - rjacobsen0
我还应该提到,我尝试了var requestMessageContent = request.Content.ToString();但是得到了一个System.NullReferenceException异常,所以这不是一个解决方案。 - rjacobsen0
看一下我对类似问题给出的答案:https://dev59.com/SlQJ5IYBdhLWcg3wQzmB#54227679 - Nkosi
1个回答

13
为了利用异步委托,请改用Returns方法。
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;
    }
}

或者考虑创建自己的处理程序,公开一个委托来处理所需的行为。

例如

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);
    }
}

并且在工厂中像这样使用

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;
    }
}

谢谢。我决定做一个小而有效的改变,使用“Returns(async ...”它效果很好! - rjacobsen0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接