diff --git a/Test/Flurl.Test.Shared/Http/TestingTests.cs b/Test/Flurl.Test.Shared/Http/TestingTests.cs index 4bd5b757..568a16d1 100644 --- a/Test/Flurl.Test.Shared/Http/TestingTests.cs +++ b/Test/Flurl.Test.Shared/Http/TestingTests.cs @@ -65,6 +65,15 @@ public async Task can_setup_multiple_responses() { HttpTest.ShouldNotHaveCalled("http://www.otherapi.com/*"); } + [Test] + public async Task can_assert_query_params() { + await "http://www.api.com?x=111&y=222&z=333".GetAsync(); + HttpTest.ShouldHaveCalled("http://www.api.com*").WithQueryParam("x"); + HttpTest.ShouldHaveCalled("http://www.api.com*").WithQueryParam("y", 222); + HttpTest.ShouldHaveCalled("*").WithQueryParam("z", "*3"); + HttpTest.ShouldHaveCalled("*").WithQueryParams(new { z = 333, y = 222 }); + } + [Test] public async Task can_simulate_timeout() { HttpTest.SimulateTimeout(); diff --git a/src/Flurl.Http.Shared/Testing/HttpCallAssertion.cs b/src/Flurl.Http.Shared/Testing/HttpCallAssertion.cs index a1dc9012..6a94e64d 100644 --- a/src/Flurl.Http.Shared/Testing/HttpCallAssertion.cs +++ b/src/Flurl.Http.Shared/Testing/HttpCallAssertion.cs @@ -4,6 +4,7 @@ using System.Net.Http; using System.Text; using System.Text.RegularExpressions; +using Flurl.Util; namespace Flurl.Http.Testing { @@ -45,7 +46,40 @@ public void Times(int expectedCount) { /// Can contain * wildcard. public HttpCallAssertion WithUrlPattern(string urlPattern) { _urlPattern = urlPattern; // this will land in the exception message when we assert, which is the only reason for capturing it - return With(c => MatchesPattern(c.Request.RequestUri.AbsoluteUri, urlPattern)); + return With(c => MatchesPattern(c.Url, urlPattern)); + } + + /// + /// Asserts whether calls were made containing the given query parameter (regardless of its value). + /// + /// The query parameter name. + /// + public HttpCallAssertion WithQueryParam(string name) { + return With(c => new Url(c.Url).QueryParams.Any(q => q.Name == name)); + } + + /// + /// Asserts whether calls were made containing the given query parameter name/value. + /// + /// The query parameter name. + /// The query parameter value. Can contain * wildcard. + /// + public HttpCallAssertion WithQueryParam(string name, object value) { + return With(c => new Url(c.Url).QueryParams.Any(q => q.Name == name && MatchesPattern(q.Value.ToString(), value.ToString()))); + } + + /// + /// Asserts whether calls were made containing all of the given query parameters. + /// + /// Object (usually anonymous) or dictionary that is parsed to name/value query parameters to check for. + /// + public HttpCallAssertion WithQueryParams(object values) { + return With(c => { + var expected = values.ToKeyValuePairs().Select(kv => $"{kv.Key}={kv.Value}"); + var actual = new Url(c.Url).QueryParams.Select(q => $"{q.Name}={q.Value}"); + //http://stackoverflow.com/a/333034/62600 + return !expected.Except(actual).Any(); + }); } /// diff --git a/src/Flurl.Http.Shared/Testing/HttpTest.cs b/src/Flurl.Http.Shared/Testing/HttpTest.cs index 69aabb5b..25e93ebe 100644 --- a/src/Flurl.Http.Shared/Testing/HttpTest.cs +++ b/src/Flurl.Http.Shared/Testing/HttpTest.cs @@ -120,8 +120,8 @@ public HttpCallAssertion ShouldHaveCalled(string urlPattern) { /// Throws an HttpCallAssertException if a URL matching the given pattern was called. /// /// URL that should not have been called. Can include * wildcard character. - public HttpCallAssertion ShouldNotHaveCalled(string urlPattern) { - return new HttpCallAssertion(CallLog, true).WithUrlPattern(urlPattern); + public void ShouldNotHaveCalled(string urlPattern) { + new HttpCallAssertion(CallLog, true).WithUrlPattern(urlPattern); } ///