Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Method for validating request Content #14

Open
rlightner opened this issue Aug 24, 2022 · 2 comments
Open

Method for validating request Content #14

rlightner opened this issue Aug 24, 2022 · 2 comments

Comments

@rlightner
Copy link

Is there a way to assert on the content of the request?

I want to validate that an external library using the mocked client is sending the correct info to the endpoint.

Thanks!

@maxkagamine
Copy link
Owner

Hi Raine. There are a few ways you can do this.

SetupRequest can take a match predicate that allows you to check the request body and determine if the setup should match a request or not by returning a boolean, for cases where the method/url aren't enough. This is basically adding an extra && to the Moq matcher used internally, but what you can also do is put asserts in that function instead and just return true, like so:

handler
    .SetupRequest(HttpMethod.Post, url, async request =>
    {
        var json = await request.Content.ReadFromJsonAsync<Foo>();
        Assert.Equal(expected.Id, json.Id);
        // ...
        return true;
    })
    .ReturnsResponse(HttpStatusCode.OK);

It's abusing Moq slightly, but instead of an exception saying that the invocation didn't match a setup (or the handler returning null, in loose mode), you'll get a more useful assertion error.

Alternatively, the more conventional way would be to use Moq's Callback method to grab the request message and then do asserts later, at the bottom with other asserts:

Foo actual = null;

handler
    .SetupRequest(HttpMethod.Post, url)
    .ReturnsResponse(HttpStatusCode.OK)
    .Callback((HttpRequestMessage request, CancellationToken _) =>
    {
        actual = request.Content.ReadFromJsonAsync<Foo>().Result;
    });

// act...

Assert.Equal(expected.Id, actual?.Id);
handler.VerifyRequest(HttpMethod.Post, url, Times.Once());

ReturnsResponse should go before Callback, since the latter returns a different interface that won't have the extension method.

If you take this approach, be sure to verify the number of times it was called, too, as you'll only be asserting on the last request to have been made.

I've also seen one repo using this library make use of VerifyRequest to do the same thing as the first example but with the asserts at the bottom of the test. I actually didn't intend for this, but since the VerifyRequest extensions were generated together with the SetupRequest variants, they too have a match predicate you can use:

handler.SetupAnyRequest()
    .ReturnsResponse(HttpStatusCode.OK);

// act...

handler.VerifyRequest(HttpMethod.Post, url, async request =>
{
    var json = await request.Content.ReadFromJsonAsync<Foo>();
    Assert.Equal(expected.Id, json.Id);
    return true;
}, Times.Once());
handler.VerifyNoOtherCalls();

Keep in mind you still need some kind of setup, even if it's just a SetupAnyRequest(), but you can use VerifyNoOtherCalls() to make sure no unexpected requests were made, as shown. Also, reading the request body in Verify might not work in legacy .NET Framework; I haven't dug into it, but the old HttpClient seems to dispose of the request stream before Verify gets a chance to run.

You can see the first two in practice in the "MatchesCustomPredicate" unit test here.

@rlightner
Copy link
Author

Perfect, thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants