更方便地模拟 Http 响应

更方便地 Mock Http Response

Intro

在我们的业务代码中往往会有很多调用内部其他 team 或者是第三方的一些服务,在编写单元测试代码时,往往需要 Mock Http Response 来模拟更好可能的返回结果,我封装了一个简单的 Http Handler 来简化 Mock 过程,让基于 HttpClient Http Response 的模拟更为简单。

Sample

首先来看一个简单的使用示例,也是一个测试用例

[Theory]
[InlineData(HttpStatusCode.OK)]
[InlineData(HttpStatusCode.BadRequest)]
[InlineData(HttpStatusCode.Unauthorized)]
[InlineData(HttpStatusCode.Forbidden)]
[InlineData(HttpStatusCode.NotFound)]
[InlineData(HttpStatusCode.InternalServerError)]
public async Task HttpStatusTest(HttpStatusCode httpStatusCode)
{
    var httpHandler = new MockHttpHandler(req => new HttpResponseMessage(httpStatusCode));
    using var httpClient = new HttpClient(httpHandler);
    using var response = await httpClient.GetAsync("http://localhost:32123/api/values");
    Assert.Equal(httpStatusCode, response.StatusCode);
}

如果有需要在测试的过程中修改模拟的行为,可以通过 SetResponseFactory 方法来

[Fact]
public async Task SetResponseFactoryTest()
{
    var httpHandler = new MockHttpHandler();
    using var httpClient = new HttpClient(httpHandler);
    var response = await httpClient.GetAsync("http://localhost:32123/api/values");
    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

    httpHandler.SetResponseFactory(req => new HttpResponseMessage(HttpStatusCode.BadRequest));
    response = await httpClient.GetAsync("http://localhost:32123/api/values");
    Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}

上面的方式都是直接指定了 response,我们也可以根据请求信息动态地返回 response

[Fact]
public async Task DynamicResponseTest()
{
    var httpHandler = new MockHttpHandler(req => new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new StringContent(req.Method.Method)
    });
    using var httpClient = new HttpClient(httpHandler);
    var response = await httpClient.GetStringAsync("http://localhost:32123/api/values");
    Assert.Equal(HttpMethod.Get.Method, response);

    using var httpResponse = await httpClient.PostAsync("http://localhost:32123/api/values", new StringContent(""));
    response = await httpResponse.Content.ReadAsStringAsync();
    Assert.Equal(HttpMethod.Post.Method, response);
}

Implement

实现代码很简单,大致如下,根据自定义的逻辑去返回 response 即可

public sealed class MockHttpHandler : HttpMessageHandler
{
    private Func<HttpRequestMessage, Task<HttpResponseMessage>> _responseFactory;

    public MockHttpHandler() : this(_ => Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)))
    {
    }

    public MockHttpHandler(Func<HttpRequestMessage, HttpResponseMessage> responseFactory)
    {
        Guard.NotNull(responseFactory);
        _responseFactory = req => Task.FromResult(responseFactory(req));
    }

    public MockHttpHandler(Func<HttpRequestMessage, Task<HttpResponseMessage>> responseFactory)
    {
        Guard.NotNull(responseFactory);
        _responseFactory = responseFactory;
    }

    public void SetResponseFactory(Func<HttpRequestMessage, HttpResponseMessage> responseFactory)
    {
        Guard.NotNull(responseFactory);
        _responseFactory = req => Task.FromResult(responseFactory(req));
    }

    public void SetResponseFactory(Func<HttpRequestMessage, Task<HttpResponseMessage>> responseFactory)
    {
        Guard.NotNull(responseFactory);
        _responseFactory = responseFactory;
    }

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

More

在需要模拟 Http API 的响应时,可以考虑使用这种方式,希望对你有帮助

技术群: 需要进技术群学习交流的请添加小编微信,切记备注:加群,对以上内容有什么疑问也可以直接和小编直接沟通交流!     

小编微信:mm1552923   

公众号:dotNet编程大全   

References

  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Http/MockHttpHandler.cs

  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/test/WeihanLi.Common.Test/HttpTest/MockHttpHandlerTest.cs

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值