使用Moq模拟HttpClient [英] Mock HttpClient using Moq

查看:230
本文介绍了使用Moq模拟HttpClient的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢对使用HttpClient的类进行单元测试.我们将HttpClient对象注入到类构造函数中.

I like to unit test a class that use HttpClient. We injected the HttpClient object in the class constructor.

public class ClassA : IClassA
{
    private readonly HttpClient _httpClient;

    public ClassA(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<HttpResponseMessage> SendRequest(SomeObject someObject)
    {
        //Do some stuff

        var request = new HttpRequestMessage(HttpMethod.Post, "http://some-domain.in");

        //Build the request

        var response = await _httpClient.SendAsync(request);

        return response;
    }
}

现在,我们想对ClassA.SendRequest方法进行单元测试.我们将Ms Test用于单元测试框架,并将Moq用于模拟.

Now we like to unit test the ClassA.SendRequest method. We are using Ms Test for unit testing framework and Moq for mocking.

当我们尝试模拟HttpClient时,它会抛出NotSupportedException.

When we tried to mock the HttpClient, it throws NotSupportedException.

[TestMethod]
public async Task SendRequestAsync_Test()
{
    var mockHttpClient = new Mock<HttpClient>();

    mockHttpClient.Setup(
        m => m.SendAsync(It.IsAny<HttpRequestMessage>()))
    .Returns(() => Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));
}

我们如何解决这个问题?

How can we solve this issue?

推荐答案

该特定的重载方法不是虚拟的,因此无法被Moq覆盖.

That particular overload method is not virtual so is unable to be overridden by Moq.

public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request);

这就是为什么它抛出NotSupportedException

您正在寻找的虚拟方法就是这种方法

The virtual method you are looking for is this method

public virtual Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);

但是模拟HttpClient并不像使用其内部消息处理程序那样简单.

However mocking HttpClient is not as simple as it seems with its internal message handler.

我建议使用带有自定义消息处理程序存根的具体客户端,以便在伪造请求时提供更大的灵活性.

I suggest using a concrete client with a custom message handler stub that will allow for more flexibility when faking the request.

这里是委派处理程序存根的示例.

Here is an example of a delegating handler stub.

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

请注意,默认构造函数基本上是在做您以前尝试模仿的事情.它还允许带有请求委托的更多自定义方案.

Note the default constructor is doing basically what you were trying to mock before. It also allows for more custom scenarios with a delegate for the request.

使用存根,可以将测试重构为类似的内容

With the stub, the test can be refactored to something like

public async Task _SendRequestAsync_Test() {
    //Arrange           
    var handlerStub = new DelegatingHandlerStub();
    var client = new HttpClient(handlerStub);
    var sut = new ClassA(client);
    var obj = new SomeObject() {
        //Populate
    };

    //Act
    var response = await sut.SendRequest(obj);

    //Assert
    Assert.IsNotNull(response);
    Assert.IsTrue(response.IsSuccessStatusCode);
}

这篇关于使用Moq模拟HttpClient的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆