Pact Consumer Swift
This library provides a Swift / Objective C DSL for creating Consumer Pacts.
Implements Pact Specification v2, including flexible matching.
This DSL relies on the Ruby pact-mock_service gem to provide the mock service for the tests.
Installation
Note: see Upgrading for notes on upgrading from 0.2 to 0.3
pact-mock_service
Install thegem install pact-mock_service -v 0.9.0
Add the PactConsumerSwift library to your project
Carthage library manager
Using- See the PactSwiftExample for an example project using the library with Carthage.
Using CocoaPods
- See the PactObjectiveCExample for an example project using the library with CocoaPods.
Writing Pact Tests
Testing with Swift
Write a Unit test similar to the following (NB: this example is using the Quick test framework)
import PactConsumerSwift
...
beforeEach {
animalMockService = MockService(provider: "Animal Service", consumer: "Animal Consumer Swift")
animalServiceClient = AnimalServiceClient(baseUrl: animalMockService!.baseUrl)
}
it("gets an alligator") {
animalMockService!.given("an alligator exists")
.uponReceiving("a request for an alligator")
.withRequest(method:.GET, path: "/alligator")
.willRespondWith(status:200,
headers: ["Content-Type": "application/json"],
body: ["name": "Mary"])
//Run the tests
animalMockService!.run { (testComplete) -> Void in
animalServiceClient!.getAlligator { (alligator) in
expect(alligator.name).to(equal("Mary"))
testComplete()
}
}
}
An optional timeout
(seconds) parameter can be included on the run function. This defaults to 30 seconds.
...
animalMockService!.run(timeout: 60) { (testComplete) -> Void in
animalServiceClient!.getAlligator { (alligator) in
expect(alligator.name).to(equal("Mary"))
testComplete()
}
}
Testing with Objective-C
Write a Unit test similar to the following
@import PactConsumerSwift;
...
- (void)setUp {
[super setUp];
self.animalMockService = [[MockService alloc] initWithProvider:@"Animal Provider"
consumer:@"Animal Service Client Objective-C"];
self.animalServiceClient = [[OCAnimalServiceClient alloc] initWithBaseUrl:self.animalMockService.baseUrl];
}
- (void)testGetAlligator {
typedef void (^CompleteBlock)();
[[[[self.animalMockService given:@"an alligator exists"]
uponReceiving:@"oc a request for an alligator"]
withRequestHTTPMethod:PactHTTPMethodGET
path:@"/alligator"
query:nil headers:nil body:nil]
willRespondWithHTTPStatus:200
headers:@{@"Content-Type": @"application/json"}
body: @"{ \"name\": \"Mary\"}" ];
[self.animalMockService run:^(CompleteBlock testComplete) {
Animal *animal = [self.animalServiceClient getAlligator];
XCTAssertEqualObjects(animal.name, @"Mary");
testComplete();
}];
}
An optional timeout
(seconds) parameter can be included on the run function. This defaults to 30 seconds.
...
[self.animalMockService run:^(CompleteBlock testComplete) {
Animal *animal = [self.animalServiceClient getAlligator];
XCTAssertEqualObjects(animal.name, @"Mary");
testComplete();
} timeout:60];
}
Matching
In addition to verbatim value matching, you have 3 useful matching functions
in the Matcher
class that can increase expressiveness and reduce brittle test
cases.
Matcher.term(matcher, generate)
- tells Pact that the value should match using a given regular expression, usinggenerate
in mock responses.generate
must be a string.Matcher.somethingLike(content)
- tells Pact that the value itself is not important, as long as the element type (valid JSON number, string, object etc.) itself matches.Matcher.eachLike(content, min)
- tells Pact that the value should be an array type, consisting of elements like those passed in.min
must be >= 1.content
may be a valid JSON value: e.g. strings, numbers and objects.
NOTE: One caveat to note, is that you will need to use valid Ruby regular expressions and double escape backslashes.
See the PactSpecs.swift
, PactObjectiveCTests.m
for examples on how to expect error responses, how to use query params, and the Matchers.
For more on request / response matching, see Matching.
Verifying your iOS client against the service you are integrating with
If your setup is correct and your tests run against the pack mock server, then you should see a log file here:
$YOUR_PROJECT/tmp/pact.log
And the generated pacts, here:
$YOUR_PROJECT/tmp/pacts/...
See Verifying pacts for more information.
For an end to end example with a ruby back end service, have a look at the KatKit example. Here is an article using a dockerized nodejs service which uses provider states.
More reading
- The Pact website Pact
- The pact mock server that the Swift library uses under the hood Pact mock service
- A pact broker for managing the generated pact files (so you don't have to manually copy them around!) Pact broker
Contributing
Please read CONTRIBUTING.md