Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

A Swift / ObjeciveC DSL for creating pacts.

License

NotificationsYou must be signed in to change notification settings

DiUS/pact-consumer-swift

Repository files navigation

BuildCodecovCarthage compatibleSwift Package ManagerSwiftBadge w/ CocoaPod VersionBadge w/ Supported PlatformsLicense: MITTwitter


A new version featuringPact Specification v3, a simplified installation and better management of the mock server processes is in active development and can be found atPactSwift. We are currently looking for people to try it out and provide feedback.

This library provides a Swift / Objective C DSL for creating ConsumerPacts. It provides support forConsumer Driven Contract Testing between dependent systems where the integration is based on HTTP (or message queues for some of the implementations).

But why? To test communication boundaries between your app and services.You can view a presentation on how Pact can work in a mobile context here:Yow! Connected 2016 Andrew Spinks - Increasing The Confidence In Your Service Integrations.

ImplementsPact Specification v2,includingflexible matching.

This DSL relies on the Rubypact-ruby-standalone (brew tap) to provide the mock service for the tests.

Installation

Note: seeUpgrading for notes on upgrading from 0.2 to 0.3

Install Pact Mock Service

Homebrew

brew tap pact-foundation/pact-ruby-standalonebrew install pact-ruby-standalone

This will install the following tools:

pactpact-brokerpact-messagepact-mock-servicepact-provider-verifierpact-publishpact-stub-service

Manually

Alternatively you can download and install thepact-ruby-standalone archives for your platform and install as per installation instructions written inPact Ruby Standalone release notes.

Xcode Setup

In Xcode, edit your scheme and addpre- andpost-actions toTest to start and stoppact-mock-service. Make sure you select your target inProvide build settings from the drop down menu.

# Pre-actionsPATH=/path/to/your/standalone/pact/bin:$PATHpact-mock-service start --pact-specification-version 2.0.0 --log "${SRCROOT}/tmp/pact.log" --pact-dir "${SRCROOT}/tmp/pacts" -p 1234# Post-actionsPATH=/path/to/your/standalone/pact/bin:$PATHpact-mock-service stop

Note: your generated Pact files will be dropped into"${SRCROOT}/tmp/pacts" folder.

Xcode Scheme Test Pre-actions

Add the PactConsumerSwift library to your project

  • See thePactSwiftExampleSwift, Carthage Example - Build Status for an example project usingpact-consumer-swift with Carthage for an iOS target.
  • See thePactMacOSExampleBuild for an example project usingpact-consumer-swift through Carthage for a macOS target.
  • See thePactObjectiveCExampleBuild Status for an example project usingpact-consumer-swift with CocoaPods for an iOS target.
  • See thePactSwiftPMExampleBuild for an example project usingpact-consumer-swift library through Swift Package Manager for an executable that runs in terminal.

Writing Pact Tests

Testing with Swift

Write a Unit test similar to the following (NB: this example is using theQuick 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)->Voidin      animalServiceClient!.getAlligator{(alligator)inexpect(alligator.name).to(equal("Mary"))testComplete()}}}

An optionaltimeout (seconds) parameter can be included on the run function. This defaults to 30 seconds.

...    animalMockService!.run(timeout:60){(testComplete)->Voidin      animalServiceClient!.getAlligator{(alligator)inexpect(alligator.name).to(equal("Mary"))testComplete()}}

Testing with Objective-C

Write a Unit test similar to the following

@import PactConsumerSwift;...- (void)setUp {  [supersetUp];  self.animalMockService = [[MockServicealloc]initWithProvider:@"Animal Provider"consumer:@"Animal Service Client Objective-C"];  self.animalServiceClient = [[OCAnimalServiceClientalloc]initWithBaseUrl:self.animalMockService.baseUrl];}- (void)testGetAlligator {typedefvoid (^CompleteBlock)();  [[[[self.animalMockServicegiven:@"an alligator exists"]uponReceiving:@"oc a request for an alligator"]withRequestHTTPMethod:PactHTTPMethodGETpath:@"/alligator"query:nilheaders:nilbody:nil]willRespondWithHTTPStatus:200headers:@{@"Content-Type":@"application/json"}body:@"{\"name\":\"Mary\"}" ];  [self.animalMockServicerun:^(CompleteBlock testComplete) {      Animal *animal = [self.animalServiceClientgetAlligator];XCTAssertEqualObjects(animal.name,@"Mary");testComplete();  }];}

An optionaltimeout (seconds) parameter can be included on the run function. This defaults to 30 seconds.

...  [self.animalMockServicerun:^(CompleteBlock testComplete) {      Animal *animal = [self.animalServiceClientgetAlligator];XCTAssertEqualObjects(animal.name,@"Mary");testComplete();  }timeout:60];}

Testing with XCTest

Write a Unit Test similar to the following:

import PactConsumerSwift...varanimalMockService:MockService?varanimalServiceClient:AnimalServiceClient?overridefunc setUp(){    super.setUp()    animalMockService=MockService(provider:"Animal Provider", consumer:"Animal Service Client")    animalServiceClient=AnimalServiceClient(baseUrl: animalMockService!.baseUrl)}func testItGetsAlligator(){    // Prepare the expecated behaviour using pact's MockService    animalMockService!.given("an alligator exists").uponReceiving("a request for alligator").withRequest(method:.GET, path:"/alligator").willRespondWith(status:200,                       headers:["Content-Type":"application/json"],                       body:["name":"Mary"])    // Run the test    animalMockService!.run(timeout:60){(testComplete)->Voidinself.animalServiceClient!.getAlligator{(response)->inXCTAssertEqual(response.name,"Mary")testComplete()}}}...

An optionaltimeout (seconds) parameter can be included on the run function. Defaults to 30 seconds.

...    // Run the test    animalMockService!.run(timeout:60){(testComplete)->Voidinself.animalServiceClient!.getAlligator{(response)->inXCTAssertEqual(response.name,"Mary")testComplete()}}

For an example on how to test overhttps seePactSSLSpec.swift.

Matching

In addition to verbatim value matching, you have 3 useful matching functionsin theMatcher class that can increase expressiveness and reduce brittle testcases.

  • Matcher.term(matcher, generate) - tells Pact that the value should match usinga given regular expression, usinggenerate in mock responses.generate must bea string.
  • Matcher.somethingLike(content) - tells Pact that the value itself is not important, as longas the elementtype (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 maybe a valid JSON value: e.g. strings, numbers and objects.

NOTE: One caveat to note, is that you will need to use valid Rubyregular expressions and double escape backslashes.

See thePactSpecs.swift,PactObjectiveCTests.m for examples on how to expect error responses, how to use query params, and Matchers.

For more on request / response matching, see [Matching][getting_started/matching].

Using in your CI

Xcode'spre-actions andpost-actions do not honour non-zero script exits and therefore would not fail your build if publishing to a Pact Broker would fail. If you would like to upload your Pact files to a Pact Broker as part of your CI, we would suggest that you create a separate step in your CI workflow with that responsibility.

Seepact-ruby-standalone page for installation instructions and how to usepact-broker client.

Verifying your 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.logAnd the generated pacts here:$YOUR_PROJECT/tmp/pacts/...

Publish your generated pact file(s) to yourPact Broker or aHosted Pact Broker so yourAPI provider can always retrieve them from one location, even when pacts change. Or even just by simply sending the pact file to your API provider devs so they can used them in their tests of their API responses. SeeVerifying pacts for more information.For an end-to-end example with a ruby back end service, have a look at theKatKit example.

Also, check out this article onusing a dockerized Node.js service that uses provider states.

More reading

  • The Pact websitePact
  • The pact mock server that the Swift library uses under the hoodPact 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 readCONTRIBUTING.md


[8]ページ先頭

©2009-2025 Movatter.jp