4

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

我在 .Net Core 3.1 中这样做

我需要嘲笑这个。根据这个问题“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)不得用于设置/验证表达式。

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

任何人都可以提供任何指示吗?

4

2 回答 2

8

IHttpClientFactory有一个方法,Create(string). 它还有一个Create(IHttpClientFactory)使用默认配置的扩展方法(它通过了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();

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

于 2020-06-22T11:08:55.240 回答
1

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

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

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

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

于 2020-06-22T10:41:39.063 回答