LoginSignup
0
1

More than 1 year has passed since last update.

.NET 単体テストで IHttpClientFactory を使うメソッドを Mock する

Posted at

毎回テストを書こうとするたびに忘れてしまうのでメモ。

テスト対象のコードはこんな感じ。

public class ProductClass
{
    public ProductClass(IHttpClientFactory httpClientFactory)
    {
        HttpClientFactory = httpClientFactory;
    }

    public IHttpClientFactory HttpClientFactory { get; }

    public async Task<ResponseObject> Get()
    {
        using var client = HttpClientFactory.CreateClient("ClientName");
        using var request = new HttpRequestMessage(HttpMethod.Get, "/request/path");

        var response = await client.SendAsync(request).ConfigureAwait(false);
        if (!response.IsSuccessStatusCode)
        {
            return null;
        }
        var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

        return JsonConvert.DeserializeObject<ResponseObject>(json);
    }
}

テストコードはこうなる。
ポイントは Moq.Protected を使って HttpMessageHandler をモックすること。

[TestFixture]
[TestOf(typeof(ProductClass))]
public class ProductClassTests
{
    [Test]
    public async Task Get()
    {
        var responseObject = new ResponseObject
        {
            SomeProperty = "value"
        };
        var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
        mockHttpMessageHandler.Protected()
            .Setup<Task<HttpResponseMessage>>(
                "SendAsync",
                ItExpr.IsAny<HttpRequestMessage>(),
                ItExpr.IsAny<CancellationToken>())
            .Returns(() =>
            {
                var response = new HttpResponseMessage
                {
                    StatusCode = HttpStatusCode.OK,
                    Content = new StringContent(JsonSerializer.Serialize(responseObject))
                };
                return Task.FromResult(response);
            });

        var baseUrl = "https://test.example.jp";
        var httpClient = new HttpClient(mockHttpMessageHandler.Object)
        {
            BaseAddress = new Uri(baseUrl)
        };

        var mockHttpClientFactory = new Mock<IHttpClientFactory>();
        mockHttpClientFactory.Setup(m => m.CreateClient(It.IsAny<string>())).Returns(httpClient);

        var targetClient = new MedicalInstituteClient(mockHttpClientFactory.Object);
        var result = await targetClient.Get();

        Assert.That(result, Is.Not.Null);
        Assert.That(result.SomeProperty, Is.EqualTo("value"));

        mockHttpMessageHandler.Protected()
            .Verify(
                "SendAsync",
                Times.Once(),
                ItExpr.Is<HttpRequestMessage>(
                    request => request.Method == HttpMethod.Get
                    && request.RequestUri == new Uri($"{baseUrl}/request/path")),
                ItExpr.IsAny<CancellationToken>());

        mockHttpClientFactory.Verify(m => m.CreateClient(It.Is<string>(s => s == "ClientName")), Times.Once());
    }
}

参考サイト
Mocking HttpClient SendAsync

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1