首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >嘲弄IHttpClientFactory - xUnit C#

嘲弄IHttpClientFactory - xUnit C#
EN

Stack Overflow用户
提问于 2019-12-08 17:12:53
回答 1查看 609关注 0票数 2

我试图在我的项目中构建一个通用的HTTP服务(c#和.net核心2.1),并且我已经按照下面的代码片段HttpService完成了它。

我也开始使用它,从我的业务逻辑类调用它,它使用这个通用的PostAsync方法将一个HTTP调用发布到一个具有正文内容的第三方。它工作得很完美。

但是,当我试着测试它时,我失败了!实际上,当我尝试调试(测试模式)时,即使在使用假对象和模拟的情况下,调试器来到这一行null时,也会得到var result = await _httpService.PostAsync("https://test.com/api", content);响应,尽管它在调试模式下正常工作,没有测试/模拟。

HTTP服务:

代码语言:javascript
复制
public interface IHttpService
{
    Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content);
}

public class HttpService : IHttpService
{
    private readonly IHttpClientFactory _httpClientFactory;

    public HttpService(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    public async Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
    {
        var httpClient = _httpClientFactory.CreateClient();
        httpClient.Timeout = TimeSpan.FromSeconds(3);
        var response = await httpClient.PostAsync(requestUri, content).ConfigureAwait(false);
        response.EnsureSuccessStatusCode();

        return response;
    }
}

商务舱:

代码语言:javascript
复制
public class Processor : IProcessor
{
    private readonly IHttpService _httpService;

    public Processor() { }

    public Processor(IHttpService httpService, IAppSettings appSettings)
    {
        _httpService = httpService;
    }

    public async Task<HttpResponseMessage> PostToVendor(Order order)
    {
        // Building content
        var json = JsonConvert.SerializeObject(order, Formatting.Indented);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        // HTTP POST
        var result = await _httpService.PostAsync("https://test.com/api", content); // returns null during the test without stepping into the method PostAsyn itself

        return result;
    }
}

测试类:

代码语言:javascript
复制
public class MyTests
{
    private readonly Mock<IHttpService> _fakeHttpMessageHandler;
    private readonly IProcessor _processor; // contains business logic
    private readonly Fixture _fixture = new Fixture();

    public FunctionTest()
    {
        _fakeHttpMessageHandler = new Mock<IHttpService>();
        _processor = new Processor(_fakeHttpMessageHandler.Object);
    }

    [Fact]
    public async Task Post_To_Vendor_Should_Return_Valid_Response()
    {
        var fakeHttpResponseMessage = new Mock<HttpResponseMessage>(MockBehavior.Loose, new object[] { HttpStatusCode.OK });

        var responseModel = new ResponseModel
        {
            success = true,
            uuid = Guid.NewGuid().ToString()
        };

        fakeHttpResponseMessage.Object.Content = new StringContent(JsonConvert.SerializeObject(responseModel), Encoding.UTF8, "application/json");

        var fakeContent = _fixture.Build<DTO>().Create(); // DTO is the body which gonna be sent to the API
        var content = new StringContent(JsonConvert.SerializeObject(fakeContent), Encoding.UTF8, "application/json");

        _fakeHttpMessageHandler.Setup(x => x.PostAsync(It.IsAny<string>(), content))
            .Returns(Task.FromResult(fakeHttpResponseMessage.Object));

        var res = _processor.PostToVendor(fakeContent).Result;
        Assert.NotNull(res.Content);
        var actual = JsonConvert.SerializeObject(responseModel);
        var expected = await res.Content.ReadAsStringAsync();
        Assert.Equal(expected, actual);
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-08 17:21:13

您的问题在于模拟设置:

代码语言:javascript
复制
_fakeHttpMessageHandler.Setup(x => x.PostAsync(It.IsAny<string>(), content))
        .Returns(Task.FromResult(fakeHttpResponseMessage.Object));

PostAsync方法的第二个参数应该是content,但是由于StringContent是一个引用类型,所以在StringContent中设置的content与在处理器中创建的content不同。如果您将它更改为下一个,它应该会像您预期的那样工作:

代码语言:javascript
复制
    _fakeHttpMessageHandler.Setup(x => x.PostAsync(It.IsAny<string>(), It.IsAny<StringContent>()))
        .Returns(Task.FromResult(fakeHttpResponseMessage.Object));

对PostAsync的空响应意味着该方法具有默认设置,这意味着它将返回默认值

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59237827

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档