C#模拟IHTTP客户和;CreateClient

C#模拟IHTTP客户和;CreateClient,c#,unit-testing,mocking,moq,xunit,C#,Unit Testing,Mocking,Moq,Xunit,我有一个我想进行x单元测试的函数,但似乎我必须模拟CreateClient函数?每当我在测试期间调试它时,var客户机似乎等于null。我正在正确地注入依赖项,我确信这一点。我想知道的是如何模拟CreateClient 以下是该函数: public async Task CreateMessageHistoryAsync(Message message) { //This seems to be giving a null value var cl

我有一个我想进行x单元测试的函数,但似乎我必须模拟CreateClient函数?每当我在测试期间调试它时,var客户机似乎等于null。我正在正确地注入依赖项,我确信这一点。我想知道的是如何模拟CreateClient

以下是该函数:

    public async Task CreateMessageHistoryAsync(Message message)
    {
        //This seems to be giving a null value
        var client = this.clientFactory.CreateClient(NamedHttpClients.COUCHDB);

        var formatter = new JsonMediaTypeFormatter();
        formatter.SerializerSettings = new JsonSerializerSettings
        {
            Formatting = Formatting.Indented,
            NullValueHandling = NullValueHandling.Ignore,
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };

        Guid id = Guid.NewGuid();            

        var response = await client.PutAsync(id.ToString(), message, formatter);

        if (!response.IsSuccessStatusCode)
        {
            throw new HttpRequestException(await response.Content.ReadAsStringAsync());
        }
    }
这是单元测试,我在一个单独的类中模拟IHttpClient,并使用该类

    [Collection("MockStateCollection")]
    public class CreateMessageHistory
    {
        private readonly MockStateFixture mockStateFixture;

        public CreateMessageHistory(MockStateFixture mockStateFixture)
        {
            this.mockStateFixture = mockStateFixture;
        }

        [Fact]
        public async Task Should_NotThrowHttpRequestException_When_AMessageHistoryIsCreated()
        {
            var recipients = MockMessage.GetRecipients("Acc", "Site 1", "Site 2", "Site 3");
            var message = MockMessage.GetMessage(recipients);

            mockStateFixture
                .MockMessageHistoryService
                .Setup(service => service.CreateMessageHistoryAsync(message));

            var messageHistoryService = new MessageHistoryService(
                mockStateFixture.MockIHttpClientFactory.Object);

            mockStateFixture.MockIHttpClientFactory.Object.CreateClient("CouchDB");

            var task = messageHistoryService.CreateMessageHistoryAsync(message);
            var type = task.GetType();
            Assert.True(type.GetGenericArguments()[0].Name == "VoidTaskResult");
            Assert.True(type.BaseType == typeof(Task));
            await task;

            //await Assert.IsType<Task>(messageHistoryService.CreateMessageHistoryAsync(message));
            // await Assert.ThrowsAsync<HttpRequestException>(() => messageHistoryService.CreateMessageHistoryAsync(message));
        }
    }
[集合(“MockStateCollection”)]
公共类CreateMessageHistory
{
私有只读MockStateFixture MockStateFixture;
public CreateMessageHistory(MockStateFixture MockStateFixture)
{
this.mockStateFixture=mockStateFixture;
}
[事实]
创建消息历史记录()时,公共异步任务不应通过whttprequesteexception
{
var recipients=MockMessage.GetRecipients(“Acc”、“站点1”、“站点2”、“站点3”);
var message=MockMessage.GetMessage(收件人);
模拟固定装置
.MockMessageHistoryService
.Setup(service=>service.CreateMessageHistoryAsync(message));
var messageHistoryService=newmessagehistoryservice(
mockStateFixture.MockIHttpClientFactory.Object);
mockStateFixture.MockIHttpClientFactory.Object.CreateClient(“CouchDB”);
var task=messageHistoryService.createMessageHistorySync(消息);
var type=task.GetType();
Assert.True(type.GetGenericArguments()[0]。Name==“VoidTaskResult”);
True(type.BaseType==typeof(Task));
等待任务;
//等待Assert.IsType(messageHistoryService.CreateMessageHistorySync(message));
//等待Assert.ThrowsAsync(()=>messageHistoryService.CreateMessageHistorySync(message));
}
}

在我看来,我还需要模拟CreateClient类,是吗?

您应该为
ClientFactory
注入模拟对象,您已经为其设置了
CreateClient
方法

// create the mock client
var httpClient = new Mock<IHttpClient>();

// setup method call for client
httpClient.Setup(x=>x.PutAsync(It.IsAny<string>()
                               , It.IsAny<Message>(),
                               , It.IsAny< JsonMediaTypeFormatter>())
          .Returns(Task.FromResult(new HttpResponseMessage { StatusCode = StatusCode.OK}));

// create the mock client factory mock
var httpClientFactoryMock = new Mock<IHttpClientFactory>();

// setup the method call
httpClientFactoryMock.Setup(x=>x.CreateClient(NamedHttpClients.COUCHDB))
                     .Returns(httpClient);
更新

为了单元测试
HttpClient
,因为它没有任何接口,所以应该按照描述的方式包装它

具体而言,我们必须按照以下方式安排http客户端:

// Mock the handler
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);

handlerMock.Protected()
// Setup the PROTECTED method to mock
           .Setup<Task<HttpResponseMessage>>("PutAsync",
                                             ItExpr.IsAny<String>(),
                                             ItExpr.IsAny<Message>()
                                             ItExpr.IsAny<MediaTypeFormatter>())
// prepare the expected response of the mocked http call
           .ReturnsAsync(new HttpResponseMessage()
           {
               StatusCode = HttpStatusCode.OK
           })
           .Verifiable();

// use real http client with mocked handler here
var httpClient = new HttpClient(handlerMock.Object)
{
    BaseAddress = new Uri("http://test.com/"),
};

你在嘲笑一个单独的班级,你在哪里?我们需要看看你在那门课上做什么。请发布代码。没有IHttpClient,只有HttpClient,这是打字错误吗?我将其更改为HttpClient,但方法调用的where part//setup给出了一个错误:无法将“Moq.Mock转换为'System.Net.HttpClient'@IvanApungan我错认为您的客户端实现了一个接口,它是实际的
HttpClient
。请检查我的更新。那里的链接将指导您如何模拟http客户端。因此,您应该仅更改上述内容,并使httpClientFactory返回此内容。如果有什么不清楚的,请告诉我。先生,您是一位传奇人物!多谢各位@伊万纳邦安,非常欢迎你!我很高兴我帮了忙:)@Christos您应该使用正确的HttpClient和消息处理程序示例更新您的答案,因为没有IHttpClient。
// Mock the handler
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);

handlerMock.Protected()
// Setup the PROTECTED method to mock
           .Setup<Task<HttpResponseMessage>>("PutAsync",
                                             ItExpr.IsAny<String>(),
                                             ItExpr.IsAny<Message>()
                                             ItExpr.IsAny<MediaTypeFormatter>())
// prepare the expected response of the mocked http call
           .ReturnsAsync(new HttpResponseMessage()
           {
               StatusCode = HttpStatusCode.OK
           })
           .Verifiable();

// use real http client with mocked handler here
var httpClient = new HttpClient(handlerMock.Object)
{
    BaseAddress = new Uri("http://test.com/"),
};
// create the mock client factory mock
var httpClientFactoryMock = new Mock<IHttpClientFactory>();

// setup the method call
httpClientFactoryMock.Setup(x=>x.CreateClient(NamedHttpClients.COUCHDB))
                     .Returns(httpClient);