如何正确的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);
        }
    }

通常,我们对不便于进行单元测试的类可以添加辅助类进行封装,这是一种常用的策略。

posted @ 2021-07-19 14:43  SilverFox8588  阅读(102)  评论(0编辑  收藏  举报