Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Argument matching not working properly with NSubstitute

I have this code and I can't get httpClient to return the string response no matter what.

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

Here is the StringResponse method if someone wants to reproduce this:

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

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

    return response;
}

What am I doing wrong?

It works when I do

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

But I don't need just any arguments, I need one of them to be the string "/login" and the other to be of type StringContent.

I tried to put something more general in the Arg.Is call like HttpContent but that doesn't work too.

I'm using NSubstitute 2.0.0-rcon .NET Core, but I also tried using NSubstitute 1.10.0 on standart console application and got the same result.

like image 229
Hristo Kolev Avatar asked Mar 12 '23 00:03

Hristo Kolev


1 Answers

The problem here is that the public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content) method isn't virtual and NSubstitute cannot correctly link your argument specification and return value to the method. That's a problem of all mocking libraries based on Castle.Core.

What's important is that NSubstitute links the specification to the first virtual method in the execution stack which turns out to be public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) method somewhere down the stack. You were "lucky" to have the same return type in it. And as you can see it has different arguments that obviously don't match with those you provided. Surprisingly ReturnsForAnyArgs() works because it doesn't check the argument specification you provided.

like image 164
Alexandr Nikitin Avatar answered Mar 24 '23 15:03

Alexandr Nikitin