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

False positive on _httpTest.ShouldHaveCalled() #323

Closed
LUS1N opened this issue May 31, 2018 · 9 comments
Closed

False positive on _httpTest.ShouldHaveCalled() #323

LUS1N opened this issue May 31, 2018 · 9 comments
Labels

Comments

@LUS1N
Copy link

LUS1N commented May 31, 2018

I don't know if it's intended behavior, but it got me sidetracked a bit and I had to make special checking that would be avoided if this worked as expected.

I ran into the issue that when confirming that a url was called, the HttpTest library doesn't compare if the urls are equal but only if the test url is in the called url. Even though there are no wildcards.

Calling /something and /something/1/else/3 are very different things, but the test sees them as equivalent.

To recreated - this test will pass:

using System.Net.Http;
using Flurl;
using Flurl.Http;
using Flurl.Http.Testing;
using Xunit;

namespace FlurlTest
{
    public class MyWebClient
    {
        public string DoThing()
        {
            var url = "https://example.com"
                .AppendPathSegment("somePath/asd/asd");

            var response = url.PostJsonAsync(new { name = "TestBoi" }).Result;

            return response.Content.ReadAsStringAsync().Result;
        }
    }

    public class UnitTest1
    {
        private readonly HttpTest _httpTest;

        public UnitTest1()
        {
            _httpTest = new HttpTest();
        }

        [Fact]
        public void Test1()
        {
            _httpTest.RespondWithJson(new
            {
                ok = true,
                user = new
                {
                    id = "123"
                }
            });

            var client = new MyWebClient();
            var result = client.DoThing();

            _httpTest.ShouldHaveCalled("https://example.com/somePath")
                .WithVerb(HttpMethod.Post)
                .Times(1);
        }
    }
}

.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>

    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Flurl.Http" Version="2.3.1" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
    <PackageReference Include="xunit" Version="2.3.1" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
    <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
  </ItemGroup>

</Project>
@tmenier
Copy link
Owner

tmenier commented Jun 4, 2018

This is a tough call. I'm inclined to agree with you about how it probably should work, but this would be a breaking change that could affect lots of people. I can also kind of see a counter-argument for something like query strings. If your code calls https://api.com/endpoint?x-y, then should this pass?

test.ShouldHaveCalled("https://api.com/endpoint");

Some might say yes. If I had it to do all over again, I'd probably say no, just put a * at the end of it if it might have a query string. But as it is, I don't think I want to take the breaking change at least until the next major version.

I'll keep this open. Maybe there should just be a new method like ShouldHaveCalledExact (and better documentation of ShouldHaveCalled). I'll give it some thought. Thanks for bringing it up.

@tmenier tmenier added this to the Flurl.Http 3.0 milestone Jul 2, 2018
@bchavez
Copy link

bchavez commented Nov 5, 2018

Here's how I resolved the issue (with Fluent Assertions):

public static HttpCallAssertion ShouldHaveExactCall(this HttpTest test, string exactUrl)
{
   test.CallLog.First().FlurlRequest.Url.ToString().Should().Be(exactUrl);
   return new HttpCallAssertion(test.CallLog);
}

The reason I needed to match exact URLs was because I had two distinct endpoints /users and /user and was bewildered why following unit test passed:

using( var test = new HttpTest() ){

   var response =  await "https://test.com/v2/users"
                     .PutJsonAsync(new {foo="hi"});

   test.ShouldHaveCalled("https://test.com/v2/user");
   "test should not pass".Dump();
}

Infact, test.ShouldHaveCalled("https") would work too. The behavior of ShouldHaveCalled(...) really has a semantic nature of ShouldHaveCalledUrlStartingWith(...).

Good thing I caught this, because some API calls to /users and /user would have slipped through the cracks.

@tmenier
Copy link
Owner

tmenier commented Dec 14, 2019

This one's finally ready! As a side-note, the same simple wildcard matching is used for other things like asserting query parameters, headers, and response bodies. This will affect all of them, but I'm a little bit lenient in the case of WithConentType. If the full Content-Type header is application/json; charset=utf-8 and WithContentType("application/json") is called, that assertion will pass.

@tmenier
Copy link
Owner

tmenier commented Dec 15, 2019

Now available to test: https://www.nuget.org/packages/Flurl.Http/3.0.0-pre2

@bchavez
Copy link

bchavez commented Dec 15, 2019

Thanks a bunch Todd! :) I think this is going to really help!

@Kesmy
Copy link

Kesmy commented Mar 30, 2023

Just need to leave a note here that this change destroyed all of the testing I was previously doing with Flurl, and my tests now have to be extremely tightly coupled to implementations because of it -- instead of setting up a service with a URL base and then checking to ensure that it was used, testing now requires that you know the exact URL eventually resolved by that service implementation internally.

A ShouldHaveCalled("http://foo.com/*") also now literally expects a call of "http://foo.com/*", rather than converting it to a regex wildcard (in 3.2.4), or else this would not be an issue.

@tmenier
Copy link
Owner

tmenier commented Apr 5, 2023

@Kesmy

A ShouldHaveCalled("http://foo.com/") also now literally expects a call of "http://foo.com/"

Not true and supported by tests. Are you sure the trailing slash isn't the problem?

@Kesmy
Copy link

Kesmy commented Apr 10, 2023

It would be strange for that to be a problem.
That said, I attempted a slash, no slash, with wildcard, and without, none of which worked against a call to http://foo.com/whatever/something/athirdthing

@tmenier
Copy link
Owner

tmenier commented May 23, 2023

@Kesmy Sorry for the delay on this, been very short on time in the last couple months.

I think this issue was left open by mistake but before I close it I want to understand if there's still an issue. If you're suggesting that ShouldHaveCalled("http://foo.com/*") is NOT matching a call to a URL starting with exactly "http://foo.com/", then I'll need to see a complete example of that. There are numerous tests demonstrating this works (here for example) and I'll need to get a better understanding of what's happening in your case.

Repository owner deleted a comment from astrohart Jan 4, 2024
@tmenier tmenier closed this as completed Jan 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants