问题
I have a function that I want to x-unit test, but it seems that I have to mock the CreateClient function? Whenever I debug it during testing it seems that the var client is equals to null. I am injecting the dependencies properly, I am sure of that. What I want to know is how to mock the CreateClient.
here is that function:
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());
}
}
here is the unit test, I am mocking the IHttpClient in a separate class and I am using that class.
[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));
}
}
it seems to me that I also need to mock the CreateClient class is it?
回答1:
You should inject a mocked object for ClientFactory
for which you have setup the CreateClient
method.
// 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);
Then you have to pass the httpClientFactoryMock.Object
to the constructor:
var messageHistoryService = new MessageHistoryService(httpClientFactoryMock.Object);
Update
In order to unit test HttpClient
since it hasn't any interface you should wrap it in way as it is described here.
Specifically we have to arrange the http client as below:
// 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/"),
};
Now we should return the above httpClient
when CreateClient
is called.
// create the mock client factory mock
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
// setup the method call
httpClientFactoryMock.Setup(x=>x.CreateClient(NamedHttpClients.COUCHDB))
.Returns(httpClient);
来源:https://stackoverflow.com/questions/54200046/c-sharp-mock-ihttpclient-createclient