From 32d3c6a471548a998bc5bdcc8c401de9a80ab019 Mon Sep 17 00:00:00 2001 From: Neil Campbell Date: Tue, 26 Aug 2014 19:40:28 +1000 Subject: [PATCH] Adding some integration test for the pactbuilder failure scenarios --- .../IntegrationTestsMyApiPact.cs | 28 +++++ .../PactBuilderFailureIntegrationTests.cs | 114 ++++++++++++++++++ PactNet.Tests/PactNet.Tests.csproj | 2 + .../pacts/integrationtests-myapi.json | 54 +++++++++ .../Comparers/HttpQueryStringComparer.cs | 11 +- .../Models/ProviderServiceRequest.cs | 2 +- .../Models/ProviderServiceResponse.cs | 2 +- .../Consumer.Tests/ConsumerEventApiPact.cs | 2 +- 8 files changed, 206 insertions(+), 9 deletions(-) create mode 100644 PactNet.Tests/IntegrationTests/IntegrationTestsMyApiPact.cs create mode 100644 PactNet.Tests/IntegrationTests/PactBuilderFailureIntegrationTests.cs create mode 100644 PactNet.Tests/pacts/integrationtests-myapi.json diff --git a/PactNet.Tests/IntegrationTests/IntegrationTestsMyApiPact.cs b/PactNet.Tests/IntegrationTests/IntegrationTestsMyApiPact.cs new file mode 100644 index 00000000..7e41b195 --- /dev/null +++ b/PactNet.Tests/IntegrationTests/IntegrationTestsMyApiPact.cs @@ -0,0 +1,28 @@ +using System; +using PactNet.Mocks.MockHttpService; + +namespace PactNet.Tests.IntegrationTests +{ + public class IntegrationTestsMyApiPact : IDisposable + { + public IPactBuilder PactBuilder { get; private set; } + public IMockProviderService MockProviderService { get; private set; } + + public int MockServerPort { get { return 4321; } } + public string MockProviderServiceBaseUri { get { return String.Format("http://localhost:{0}", MockServerPort); } } + + public IntegrationTestsMyApiPact() + { + PactBuilder = new PactBuilder() + .ServiceConsumer("IntegrationTests") + .HasPactWith("MyApi"); + + MockProviderService = PactBuilder.MockService(MockServerPort); + } + + public void Dispose() + { + PactBuilder.Build(); + } + } +} \ No newline at end of file diff --git a/PactNet.Tests/IntegrationTests/PactBuilderFailureIntegrationTests.cs b/PactNet.Tests/IntegrationTests/PactBuilderFailureIntegrationTests.cs new file mode 100644 index 00000000..131d1cf7 --- /dev/null +++ b/PactNet.Tests/IntegrationTests/PactBuilderFailureIntegrationTests.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using PactNet.Mocks.MockHttpService; +using PactNet.Mocks.MockHttpService.Models; +using Xunit; + +namespace PactNet.Tests.IntegrationTests +{ + public class PactBuilderFailureIntegrationTests : IUseFixture + { + private IMockProviderService _mockProviderService; + private string _mockProviderServiceBaseUri; + + public void SetFixture(IntegrationTestsMyApiPact data) + { + _mockProviderService = data.MockProviderService; + _mockProviderServiceBaseUri = data.MockProviderServiceBaseUri; + _mockProviderService.ClearInteractions(); + } + + [Fact] + public void WhenRegisteringAnInteractionThatIsNeverSent_ThenInvalidOperationExceptionIsThrown() + { + _mockProviderService + .UponReceiving("A POST request to create a new thing") + .With(new ProviderServiceRequest + { + Method = HttpVerb.Post, + Path = "/things", + Headers = new Dictionary + { + { "Content-Type", "application/json; charset=utf-8" } + }, + Body = new + { + thingId = 1234, + type = "Awesome" + } + }) + .WillRespondWith(new ProviderServiceResponse + { + Status = 201 + }); + + Assert.Throws(() => _mockProviderService.VerifyInteractions()); + } + + [Fact] + public void WhenRegisteringAnInteractionThatIsSentMultipleTimes_ThenInvalidOperationExceptionIsThrown() + { + _mockProviderService + .UponReceiving("A GET request to retrieve a thing") + .With(new ProviderServiceRequest + { + Method = HttpVerb.Get, + Path = "/things/1234" + }) + .WillRespondWith(new ProviderServiceResponse + { + Status = 200 + }); + + var httpClient = new HttpClient {BaseAddress = new Uri(_mockProviderServiceBaseUri)}; + + var request1 = new HttpRequestMessage(HttpMethod.Get, "/things/1234"); + var request2 = new HttpRequestMessage(HttpMethod.Get, "/things/1234"); + + var response1 = httpClient.SendAsync(request1).Result; + var response2 = httpClient.SendAsync(request2).Result; + + if (response1.StatusCode != HttpStatusCode.OK || response2.StatusCode != HttpStatusCode.OK) + { + throw new Exception("Wrong status code was returned"); + } + + Assert.Throws(() => _mockProviderService.VerifyInteractions()); + } + + [Fact] + public void WhenRegisteringAnInteractionWhereTheRequestDoesNotExactlyMatchTheActualRequest_ThenInvalidOperationExceptionIsThrown() + { + _mockProviderService + .UponReceiving("A GET request to retrieve things by type") + .With(new ProviderServiceRequest + { + Method = HttpVerb.Get, + Path = "/things", + Query = "type=awesome", + Headers = new Dictionary + { + { "Accept", "application/json; charset=utf-8" } + }, + }) + .WillRespondWith(new ProviderServiceResponse + { + Status = 200 + }); + + var httpClient = new HttpClient { BaseAddress = new Uri(_mockProviderServiceBaseUri) }; + + var request = new HttpRequestMessage(HttpMethod.Get, "/things?type=awesome"); + var response = httpClient.SendAsync(request).Result; + + if (response.StatusCode != HttpStatusCode.OK || response.StatusCode != HttpStatusCode.OK) + { + throw new Exception("Wrong status code was returned"); + } + + Assert.Throws(() => _mockProviderService.VerifyInteractions()); + } + } +} diff --git a/PactNet.Tests/PactNet.Tests.csproj b/PactNet.Tests/PactNet.Tests.csproj index 4efcd8cb..f460cbb3 100644 --- a/PactNet.Tests/PactNet.Tests.csproj +++ b/PactNet.Tests/PactNet.Tests.csproj @@ -62,6 +62,8 @@ + + Code diff --git a/PactNet.Tests/pacts/integrationtests-myapi.json b/PactNet.Tests/pacts/integrationtests-myapi.json new file mode 100644 index 00000000..7925c293 --- /dev/null +++ b/PactNet.Tests/pacts/integrationtests-myapi.json @@ -0,0 +1,54 @@ +{ + "provider": { + "name": "MyApi" + }, + "consumer": { + "name": "IntegrationTests" + }, + "interactions": [ + { + "description": "A GET request to retrieve a thing", + "request": { + "method": "get", + "path": "/things/1234" + }, + "response": { + "status": 200 + } + }, + { + "description": "A GET request to retrieve things by type", + "request": { + "method": "get", + "path": "/things", + "query": "type=awesome", + "headers": { + "Accept": "application/json; charset=utf-8" + } + }, + "response": { + "status": 200 + } + }, + { + "description": "A POST request to create a new thing", + "request": { + "method": "post", + "path": "/things", + "headers": { + "Content-Type": "application/json; charset=utf-8" + }, + "body": { + "thingId": 1234, + "type": "Awesome" + } + }, + "response": { + "status": 201 + } + } + ], + "metadata": { + "pactSpecificationVersion": "1.0.0" + } +} \ No newline at end of file diff --git a/PactNet/Mocks/MockHttpService/Comparers/HttpQueryStringComparer.cs b/PactNet/Mocks/MockHttpService/Comparers/HttpQueryStringComparer.cs index 2c056e97..db5bab88 100644 --- a/PactNet/Mocks/MockHttpService/Comparers/HttpQueryStringComparer.cs +++ b/PactNet/Mocks/MockHttpService/Comparers/HttpQueryStringComparer.cs @@ -22,15 +22,14 @@ public void Compare(string expectedQuery, string actualQuery) return; } - var nomalisedExpectedQuery = ConvertUrlEncodingToUpperCase(expectedQuery); - var nomalisedActualQuery = ConvertUrlEncodingToUpperCase(actualQuery); + var normalisedExpectedQuery = ConvertUrlEncodingToUpperCase(expectedQuery); + var normalisedActualQuery = ConvertUrlEncodingToUpperCase(actualQuery); - _reporter.ReportInfo(String.Format("{0} has query set to {1}", _messagePrefix, nomalisedExpectedQuery)); - _reporter.ReportInfo(String.Format("Actual query is {0}", nomalisedActualQuery)); + _reporter.ReportInfo(String.Format("{0} has query set to {1}", _messagePrefix, normalisedExpectedQuery)); - if (nomalisedExpectedQuery != nomalisedActualQuery) + if (normalisedExpectedQuery != normalisedActualQuery) { - _reporter.ReportError(expected: nomalisedExpectedQuery, actual: nomalisedActualQuery); + _reporter.ReportError(expected: normalisedExpectedQuery, actual: normalisedActualQuery); } } diff --git a/PactNet/Mocks/MockHttpService/Models/ProviderServiceRequest.cs b/PactNet/Mocks/MockHttpService/Models/ProviderServiceRequest.cs index f1965166..0e288be5 100644 --- a/PactNet/Mocks/MockHttpService/Models/ProviderServiceRequest.cs +++ b/PactNet/Mocks/MockHttpService/Models/ProviderServiceRequest.cs @@ -18,7 +18,7 @@ public class ProviderServiceRequest public string Query { get; set; } [JsonProperty(PropertyName = "headers")] - public Dictionary Headers { get; set; } + public IDictionary Headers { get; set; } [JsonProperty(PropertyName = "body")] public dynamic Body { get; set; } diff --git a/PactNet/Mocks/MockHttpService/Models/ProviderServiceResponse.cs b/PactNet/Mocks/MockHttpService/Models/ProviderServiceResponse.cs index 9f683f10..cad7c3e3 100644 --- a/PactNet/Mocks/MockHttpService/Models/ProviderServiceResponse.cs +++ b/PactNet/Mocks/MockHttpService/Models/ProviderServiceResponse.cs @@ -9,7 +9,7 @@ public class ProviderServiceResponse public int Status { get; set; } [JsonProperty(PropertyName = "headers")] - public Dictionary Headers { get; set; } + public IDictionary Headers { get; set; } [JsonProperty(PropertyName = "body")] public dynamic Body { get; set; } diff --git a/Samples/EventApi/Consumer.Tests/ConsumerEventApiPact.cs b/Samples/EventApi/Consumer.Tests/ConsumerEventApiPact.cs index ba362ca7..bd75a3bb 100644 --- a/Samples/EventApi/Consumer.Tests/ConsumerEventApiPact.cs +++ b/Samples/EventApi/Consumer.Tests/ConsumerEventApiPact.cs @@ -9,7 +9,7 @@ public class ConsumerEventApiPact : IDisposable public IPactBuilder PactBuilder { get; private set; } public IMockProviderService MockProviderService { get; private set; } - public int MockServerPort { get { return 12345; } } + public int MockServerPort { get { return 1234; } } public string MockProviderServiceBaseUri { get { return String.Format("http://localhost:{0}", MockServerPort); } } public ConsumerEventApiPact()