NSubstitute中的参数匹配未正常工作

4

我有这段代码,无论如何都无法让httpClient返回字符串响应。

HttpClient httpClient = Substitute.For<HttpClient>();

httpClient.PostAsync("/login", Arg.Any<StringContent>())
          .Returns(this.StringResponse("{\"token\": \"token_content\"}"));

Console.WriteLine(await httpClient.PostAsync("/login", new StringContent(string.Empty)) == null); // True

如果有人想复现这个过程,这里是StringResponse方法:

private HttpResponseMessage StringResponse(string content)
{
    var response = new HttpResponseMessage(HttpStatusCode.OK);

    if (content != null)
    {
        response.Content = new StringContent(content);
    }

    return response;
}

我做错了什么?

当我这样做时,它可以正常工作

httpClient.PostAsync("/login", Arg.Any<StringContent>())
              .ReturnsForAnyArgs(this.StringResponse("{\"token\": \"token_content\"}"));

但我不仅需要任何参数,我需要其中一个是字符串"/login",另一个是StringContent类型。

我试图在Arg.Is调用中放入更通用的内容,如HttpContent,但那也不起作用。

我正在使用.NET Core上的NSubstitute 2.0.0-rc,但我也尝试在标准控制台应用程序上使用NSubstitute 1.10.0,并得到了相同的结果。


嗯,已经复制了它,但还没有成功解决它... - Jon Skeet
我怀疑这是问题所在:“警告:替换类可能会带来一些不好的副作用。首先,NSubstitute只能使用类的虚成员,因此类中的任何非虚拟代码实际上都将被执行!” PostAsync 不是一个虚方法... - Jon Skeet
这是一个非虚方法:public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content) - Fabio
NSubstitute是一种“受限制”的模拟框架 - 您只能伪造虚成员或接口。 - Fabio
我认为如果那是问题的话,它不会使用Returns而是ReturnsForAnyArgs就可以解决。 - Hristo Kolev
显示剩余6条评论
1个回答

9
问题在于public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)方法不是虚拟的,因此NSubstitute无法正确地将您的参数规范和返回值与该方法链接起来。这是基于Castle.Core的所有模拟库的问题。
重要的是,NSubstitute将规范链接到执行堆栈中的第一个虚拟方法,结果发现在堆栈的某个位置上是public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)方法。您很“幸运”,因为它具有相同的返回类型。而且,正如您所看到的,它具有明显与您提供的参数不匹配的不同参数。令人惊讶的是,ReturnsForAnyArgs()有效,因为它不检查您提供的参数规范。

1
我自己永远也想不到那个,谢谢! - Hristo Kolev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接