如何正确的Moq HttpClient in Unit Tests
对很多直接使用HttpClient对象的方法进行单元测试几乎时不可能的。我们可以采用如下方法进行测试:
1. 对创建HttpClient对象进行封装
封装HttpClient对象的类和接口很简单,只有一个Create方法来创建一个HttpClient对象。如下:
public class HttpClientHelper : IHttpClientHelper
{
public HttpClient Create()
{
var httpClient = new HttpClient();
return httpClient;
}
}
public interface IHttpClientHelper
{
HttpClient Create();
}
2. 在使用HttpClient对象的类中,直接通过接口创建 _httpClientHelper.Create()。
public class Test : ITest { private IHttpClientHelper _httpClientHelper; public Test(IHttpClientHelper httpClientHelper) { _httpClientHelper = httpClientHelper; } public async Task<string> Show() { var httpClient = _httpClientHelper.Create(); var ss = httpClient.GetAsync("http://localhost:56078/api/Value").Result; return await ss.Content.ReadAsStringAsync(); } } public interface ITest { Task<string> Show(); }
3. 这样我们对Test类的Show方法就可以用如下方法添加单元测试:
[TestFixture] public class TestTests { private Test _test; private Mock<IHttpClientHelper> _mockHttpClientHelper; [SetUp] public void SetUp() { _mockHttpClientHelper = new Mock<IHttpClientHelper>(); _test = new Test(_mockHttpClientHelper.Object); var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict); handlerMock .Protected() // Setup the PROTECTED method to mock .Setup<Task<HttpResponseMessage>>( "SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>() ) // prepare the expected response of the mocked http call .ReturnsAsync(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("value"), }) .Verifiable(); var httpClient = new HttpClient(handlerMock.Object) { BaseAddress = new Uri("http://test.com/"), }; _mockHttpClientHelper.Setup(x=>x.Create()).Returns(httpClient); } [Test] public void Show_Valid_Returns() { // Arrange // Act var result = _test.Show().Result; // Assert Assert.AreEqual("value", result); } }
通常,我们对不便于进行单元测试的类可以添加辅助类进行封装,这是一种常用的策略。