【问题标题】:Nunit 3: Test a Controller that uses IHttpClientFactory as Constructor ParameterNunit 3:测试使用 IHttpClientFactory 作为构造函数参数的控制器
【发布时间】:2022-10-15 21:15:20
【问题描述】:

我正在使用带有 IHttpClientFactory 的 .NET 6 Web API 控制器来执行外部 API 调用。因此,我有以下构造函数:

public MyController(IHttpClientFactory httpClientFactory)
{
  _httpClientFactory = httpClientFactory;
}

这是有效的,因为在我的Program.cs 中,我向我的builder.Services 添加了一个 HTTP 客户端。

在我的测试中,我如何为控制器实例化/设置httpClientFactory,因为我需要它来实例化我的控制器:var controller = new MyController(httpClientFactory); 生成错误,因为没有添加任何设置。

我在 appsettings.json 的配置中遇到了类似的问题,并通过ConfigurationBuilder 解决了,但IHttpClientFactory 似乎没有类似的问题。

如果您需要更多信息,请告诉我。谢谢!

【问题讨论】:

    标签: c# asp.net-core .net-core dotnet-httpclient httpclientfactory


    【解决方案1】:

    我尝试如下:

    [TestFixture]
        public class IndexActionTests
        {
            private HomeController controller;
    
            [SetUp]
            public void Setup()
            {
                var services = new ServiceCollection();
                services.AddHttpClient();
                var provider = services.BuildServiceProvider();
                var httpclientfactory = provider.GetService<IHttpClientFactory>();
                controller = new HomeController(httpclientfactory);
            }
    
            [Test]
            public void Test1()
            {
                var result = controller.Index();
                Assert.AreEqual(typeof(ViewResult),result.GetType());
            }
        }
    

    结果:

    【讨论】:

    • 1. 创建一个 DI 容器 2. 将DefaultHttpClientFactory 注册到其中 3. 检索工厂以通过 ctor 注入它。 <<你应该不是在单元测试中执行这些步骤。你应该嘲笑依赖项不会重新创建它们。通过您的设置,HomeController 将发出一个真正的 HTTP 请求,这不是单元测试的意图。它更接近于集成或 e2e 测试。
    【解决方案2】:

    为了能够在单元测试中使用正确模拟的IHttpClientFactory,您需要执行以下步骤:

    设置 DelegatingHandler 模拟

    var mockHandler = new Mock<DelegatingHandler>();
    mockHandler.Protected()
        .Setup<Task<HttpResponseMessage>>("SendAsync", It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>())
        .ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK))
        .Verifiable();
    mockHandler.As<IDisposable>().Setup(s => s.Dispose());
    

    此示例模拟将始终返回 200 OK 状态代码且没有响应正文

    • 根据您的需要定制设置

    创建一个HttpClient

    var httpClient = new HttpClient(mockHandler.Object);
    

    它创建一个HttpClient 实例并将上面的处理程序传递给它

    设置 IHttpClientFactory 模拟

    var mockFactory = new Mock<IHttpClientFactory>(MockBehavior.Strict);
    mockFactory
      .Setup(factory => factory.CreateClient())
      .Returns(httpClient)
      .Verifiable();
    

    它设置了一个IHttpClientFactory 模拟来返回上述HttpClient 用于CreateClient 方法调用

    • 如果您使用IHttpClientFactory 创建命名客户端,请将Setup 更改为此.Setup(factory =&gt; factory.CreateClient(It.IsAny&lt;string&gt;()))

    使用模拟对象进行验证

    mockFactory.Verify(factory => factory.CreateClient(), Times.Once); 
    mockHandler.Protected()
       .Verify("SendAsync", Times.Once(), It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-24
      • 2019-04-24
      • 2023-04-03
      • 1970-01-01
      • 2013-07-01
      • 1970-01-01
      相关资源
      最近更新 更多