Skip to content

.NET & Nsubstitute 模拟Http请求

L edited this page Mar 12, 2023 · 5 revisions

我们的代码中有时候会需要调用其他平台的接口,在做单元测试的时候,我们不需要测试这些第三方接口是否生效,接口是否有问题,但是如果我们直接调用第三方接口,这些接口的错误又会影响我们正常的测试工作,所以我们应该怎么办呢?我们可以模拟这些接口,让其返回我们期待的返回结果,这样我们就可以顺利的进行内部代码的测试了。
这里我们继承HttpMessageHandler,写一个MockHttpMessageHandler

public class MockHttpMessageHandler : HttpMessageHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return Task.FromResult(MockSend(request, cancellationToken));
    }

    protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return MockSend(request, cancellationToken);
    }

    public virtual HttpResponseMessage MockSend(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }
}

然后我们通过Substitute.ForPartsOf<T>()方法创建一个MockHttpMessageHandler对象,将其传参给HttpClient对象。

var mockHttpMessageHandler = Substitute.ForPartsOf<MockHttpMessageHandler>();
httpClient = new HttpClient(mockHttpMessageHandler);

然后通过NsubstituteReturn等方法设置返回结果HttpResponseMessage

HttpResponseMessage mockResponse = new HttpResponseMessage(HttpStatusCode.OK);
mockResponse.Content = new StringContent(returnMessage);
mockHttpMessageHandler.MockSend(Arg.Any<HttpRequestMessage>(), Arg.Any<CancellationToken>())
    .ReturnsForAnyArgs(mockResponse);

这里我们设置任意参数的MockSend方法均返回HttpStatusCode=OK,返回值为returnMessage。
在实际测试过程中,我们可以根据具体的情况返回不同的结果。
整段测试代码如下:

public class MockHttpClientUnitTest
{
    HttpClient httpClient;
    const string returnMessage = "Ok";
    public MockHttpClientUnitTest()
    {
        var mockHttpMessageHandler = Substitute.ForPartsOf<MockHttpMessageHandler>();
        httpClient = new HttpClient(mockHttpMessageHandler);
        //mock response
        HttpResponseMessage mockResponse = new HttpResponseMessage(HttpStatusCode.OK);
        mockResponse.Content = new StringContent(returnMessage);
        mockHttpMessageHandler.MockSend(Arg.Any<HttpRequestMessage>(), Arg.Any<CancellationToken>())
            .ReturnsForAnyArgs(mockResponse);
    }

    [Fact]
    public async void Test()
    {
        (await (await httpClient.GetAsync("https://cn.bing.com/")).Content.ReadAsStringAsync()).ShouldBe(returnMessage);
    }
}

示例代码

MockHttpClientUnitTest
MockHttpMessageHandler

参考资料

Partial subs and test spies
How to Mock HttpClient using NSubstitute

Clone this wiki locally