【问题标题】:Mocking an HttpClient created using IHttpClientFactory.CreateClient模拟使用 IHttpClientFactory.CreateClient 创建的 HttpClient
【发布时间】:2020-06-22 10:35:10
【问题描述】:

正如标题所示,我有一些代码调用IHttpClientFactory.CreateClient() 来创建一个HttpClient 实例。

我在 .Net Core 3.1 中这样做

我需要模拟一下。根据this question"C# Mock IHttpclient & CreateClient",以下应该可以工作...

[Test]
public void Mytest() {

    var httpClientFactory = new Mock<IHttpClientFactory>(MockBehavior.Strict);

    httpMessageHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict);
    httpMessageHandler.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.BadRequest,
        })
        .Verifiable();

    var httpClient = new HttpClient(httpMessageHandler.Object);

    httpClientFactory.Setup(_ => _.CreateClient())   // This fails
        .Returns(httpClient).Verifiable();

    systemUnderTest = new MyService(httpClientFactory.Object);
    var result = systemUnderTest.MyMethod()

    // Assert Stuff
}

但是,当我运行它时,会报告以下内容...

System.NotSupportedException:不支持的表达式:_ => _.CreateClient() 扩展方法(这里:HttpClientFactoryExtensions.CreateClient)不能在 setup / 验证表达式。

我显然做错了什么,但我看不出是什么。

谁能指点一下?

【问题讨论】:

  • 这不是一个直接的答案,但Flurl 库使使用 HttpClient 进行单元测试非常舒适。它是一个非常轻量级的 HttpClient 包装器,具有最少的依赖关系。

标签: c# unit-testing httpclientfactory


【解决方案1】:

IHttpClientFactory 有一个方法,Create(string)。它还有一个扩展方法Create(IHttpClientFactory),它使用默认配置(it passes Options.DefaultName)。

您不是在模拟接口方法,而是在模拟扩展方法,正如您已经意识到的那样,模拟扩展方法是不可能的。但不要害怕,我们有一个解决方案:模拟实际出现在界面上的方法!

您可以为所有客户端名称、特定名称或 默认 名称 (string.Empty) 模拟它:

// any name
httpClientFactory.Setup(_ => _.CreateClient(It.IsAny<string>())) 
        .Returns(httpClient).Verifiable();

// specific name
httpClientFactory.Setup(_ => _.CreateClient("SpecificName")) 
        .Returns(httpClient).Verifiable();

// the default name (extension method invokes this)
httpClientFactory.Setup(_ => _.CreateClient(string.Empty)) 
        .Returns(httpClient).Verifiable();

最后一个选项匹配调用扩展方法时发生的情况。但请记住,如果您使用 named clients,您的代码可能会将名称传递给工厂,并且您希望匹配该名称。

【讨论】:

  • 这旨在回答您的具体问题并解决所述问题。话虽如此,我同意@Paddy 的观点,因为您可能正在尝试验证错误的行为。
【解决方案2】:

似乎很像错误报告“扩展方法不可验证”,在这种情况下,CreateClient 是一个扩展方法,不能附加 Verifiable() 调用。

您希望在这里测试什么?你真的需要验证 CreateClient 是否被调用(可能不是)?确实,您是否需要验证是否调用了这些方法中的任何一个?

对我来说,应该编写此测试来检查该方法在返回“错误请求”时的输出。无需“验证”方法中的调用,因为您开始真正对方法的内部行为进行单元测试,而不是测试该方法的预期输出。

TLDR;删除验证调用并更改测试以检查预期的返回行为,而不是增加对内部实现的难以维护的检查。

【讨论】:

    猜你喜欢
    • 2023-04-10
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    相关资源
    最近更新 更多