模拟IHttpClientFactory-xUnit C#

模拟IHttpClientFactory-xUnit C#,c#,httpclient,xunit,fixtures,httpclientfactory,C#,Httpclient,Xunit,Fixtures,Httpclientfactory,我试图在我的项目中构建一个通用的HTTP服务(c#with.net core 2.1),我已经按照下面的代码片段HttpService完成了这项工作 我还通过从我的业务逻辑类调用它开始使用它,该类使用这个通用的PostAsync方法向第三方发布一个包含正文内容的HTTP调用。它工作得很好 但是,当我尝试测试它时,我失败了! 实际上,当我尝试调试(测试模式)时,当调试器到达这一行时,我得到null响应var result=wait\u httpService.PostAsync(“https://

我试图在我的项目中构建一个通用的HTTP服务(c#with.net core 2.1),我已经按照下面的代码片段
HttpService
完成了这项工作

我还通过从我的业务逻辑类调用它开始使用它,该类使用这个通用的
PostAsync
方法向第三方发布一个包含正文内容的HTTP调用。它工作得很好

但是,当我尝试测试它时,我失败了! 实际上,当我尝试调试(测试模式)时,当调试器到达这一行时,我得到
null
响应
var result=wait\u httpService.PostAsync(“https://test.com/api“,内容)在业务类
处理器中
即使使用假对象和模拟,但它在调试模式下正常工作,无需测试/模拟

HTTP服务:

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;
    }
}
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;
    }
}
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);
    }
}
公共接口IHttpService
{
任务PostAsync(字符串requestUri、HttpContent);
}
公共类HttpService:IHttpService
{
私有只读IHttpClientFactory\U httpClientFactory;
公共HttpService(IHttpClient工厂HttpClient工厂)
{
_httpClientFactory=httpClientFactory;
}
公共异步任务PostAsync(字符串请求URI,HttpContent)
{
var httpClient=_httpClientFactory.CreateClient();
httpClient.Timeout=TimeSpan.FromSeconds(3);
var response=await-httpClient.PostAsync(requestUri,content.ConfigureAwait(false);
response.EnsureSuccessStatusCode();
返回响应;
}
}
商务舱:

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;
    }
}
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;
    }
}
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);
    }
}
公共类处理器:IPProcessor
{
专用只读IHttpService_httpService;
公共处理器(){}
公共处理器(IHttpService httpService、IAppSettings appSettings)
{
_httpService=httpService;
}
公共异步任务PostToVendor(订单)
{
//建筑内容
var json=JsonConvert.serialized对象(顺序、格式、缩进);
var content=newstringcontent(json,Encoding.UTF8,“application/json”);
//HTTP POST
var result=await\u httpService.PostAsync(“https://test.com/api“,content);//在测试期间返回null,而不进入方法PostAsyn本身
返回结果;
}
}
测试类:

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;
    }
}
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;
    }
}
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);
    }
}
公共类MyTests
{
私有只读Mock_fakeHttpMessageHandler;
私有只读IPProcessor _processor;//包含业务逻辑
专用只读设备_Fixture=新设备();
公共功能测试()
{
_fakeHttpMessageHandler=new Mock();
_processor=新处理器(_fakeHttpMessageHandler.Object);
}
[事实]
公共异步任务发布到供应商应返回有效响应()
{
var fakeHttpResponseMessage=new Mock(MockBehavior.Loose,新对象[]{HttpStatusCode.OK});
var responseModel=新的responseModel
{
成功=正确,
uuid=Guid.NewGuid().ToString()
};
fakeHttpResponseMessage.Object.Content=newstringcontent(JsonConvert.SerializeObject(responseModel),Encoding.UTF8,“application/json”);
var fakeContent=_fixture.Build().Create();//DTO是要发送到API的主体
var content=newstringcontent(JsonConvert.SerializeObject(fakeContent),Encoding.UTF8,“application/json”);
_fakeHttpMessageHandler.Setup(x=>x.PostAsync(It.IsAny(),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();
断言。相等(预期、实际);
}
}

您的问题在模拟设置中:

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

p.S.对PostAsync的null响应意味着该方法具有默认设置,这意味着它将返回默认值,但您可以告诉我为什么吗?我的意思是,这是失败的根本原因吗?正如我所说,当您设置Mock时,您告诉框架当您提供特定值时应该返回什么方法。当您说It.IsAny()时,这意味着它将为任何输入返回提供的输出,但当您提供其他对象时,它正好需要该对象。如果Post方法的第二个参数具有值类型(int、double等),它将按照您的预期工作,但StringContent是一个引用类型,这就是为什么您有这个问题,那么我在这里使用的
fakeContent
就不需要了,对吗?这确实取决于您的测试用例,首先,你需要在这里传递一些东西
PostToVendor(fakeContent)
谢谢,它成功了!对于
fakeContent
它应该在那里,因为该方法最后应该有一个内容:)