pact 0.1.28 → 0.1.35

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/Gemfile.lock +5 -5
  2. data/README.md +52 -53
  3. data/example/zoo-app/Gemfile +15 -0
  4. data/example/zoo-app/Gemfile.lock +77 -0
  5. data/example/zoo-app/lib/zoo_app/animal_service_client.rb +36 -0
  6. data/example/zoo-app/lib/zoo_app/models/alligator.rb +15 -0
  7. data/example/zoo-app/spec/pacts/zoo_app-animal_service.json +100 -0
  8. data/example/zoo-app/spec/service_providers/animal_service_spec.rb +92 -0
  9. data/example/zoo-app/spec/service_providers/pact_helper.rb +11 -0
  10. data/example/zoo-app/spec/spec_helper.rb +8 -0
  11. data/lib/pact/consumer/configuration_dsl.rb +2 -0
  12. data/lib/pact/consumer/consumer_contract_builder.rb +13 -12
  13. data/lib/pact/consumer/dsl.rb +51 -2
  14. data/lib/pact/consumer/interaction.rb +15 -12
  15. data/lib/pact/consumer/mock_service.rb +31 -9
  16. data/lib/pact/consumer/mock_service_client.rb +47 -0
  17. data/lib/pact/consumer/rspec.rb +2 -1
  18. data/lib/pact/consumer_contract.rb +2 -1
  19. data/lib/pact/matchers/matchers.rb +59 -18
  20. data/lib/pact/producer/dsl.rb +61 -0
  21. data/lib/pact/producer/producer_state.rb +7 -0
  22. data/lib/pact/producer/rspec.rb +2 -0
  23. data/lib/pact/provider/rspec.rb +1 -0
  24. data/lib/pact/request.rb +42 -6
  25. data/lib/pact/verification_task.rb +2 -5
  26. data/lib/pact/version.rb +1 -1
  27. data/spec/features/consumption_spec.rb +56 -18
  28. data/spec/features/production_spec.rb +7 -16
  29. data/spec/integration/pact/consumer_configuration_spec.rb +144 -0
  30. data/spec/integration/pact/provider_configuration_spec.rb +24 -0
  31. data/spec/lib/pact/consumer/consumer_contract_builder_spec.rb +13 -13
  32. data/spec/lib/pact/consumer/dsl_spec.rb +1 -0
  33. data/spec/lib/pact/consumer/interaction_spec.rb +34 -0
  34. data/spec/lib/pact/consumer_contract_spec.rb +13 -2
  35. data/spec/lib/pact/matchers/matchers_spec.rb +32 -12
  36. data/spec/lib/pact/producer/rspec_spec.rb +1 -1
  37. data/spec/lib/pact/request_spec.rb +43 -1
  38. data/spec/support/pact_rake_support.rb +5 -8
  39. metadata +17 -10
  40. data/spec/integration/pact/configuration_spec.rb +0 -65
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pact (0.1.28)
4
+ pact (0.1.35)
5
5
  awesome_print (~> 1.1.0)
6
6
  capybara (~> 2.1.0)
7
7
  find_a_port (~> 1.0.1)
@@ -37,7 +37,7 @@ GEM
37
37
  hashie (2.0.5)
38
38
  json (1.8.0)
39
39
  method_source (0.8.1)
40
- mime-types (1.23)
40
+ mime-types (1.24)
41
41
  mini_portile (0.5.1)
42
42
  multipart-post (1.2.0)
43
43
  nokogiri (1.6.0)
@@ -55,10 +55,10 @@ GEM
55
55
  rspec-core (~> 2.14.0)
56
56
  rspec-expectations (~> 2.14.0)
57
57
  rspec-mocks (~> 2.14.0)
58
- rspec-core (2.14.4)
59
- rspec-expectations (2.14.0)
58
+ rspec-core (2.14.5)
59
+ rspec-expectations (2.14.2)
60
60
  diff-lcs (>= 1.1.3, < 2.0)
61
- rspec-mocks (2.14.1)
61
+ rspec-mocks (2.14.3)
62
62
  safe_yaml (0.9.4)
63
63
  slop (3.4.5)
64
64
  thin (1.5.1)
data/README.md CHANGED
@@ -3,28 +3,37 @@
3
3
  Define a pact between service consumers and providers.
4
4
 
5
5
 
6
- Pact provides an RSpec DSL for service consumers to define the request they will make to a service producer and the
7
- response they expect back. This expectation is used in the consumers specs to provide a mock producer, and is also
8
- played back in the producer specs to ensure the producer actually does provide the response the consumer expects.
6
+ Pact provides an RSpec DSL for service consumers to define the request they will make to a service service provider and the
7
+ response they expect back. This expectation is used in the consumers specs to provide a mock service provider, and is also
8
+ played back in the service provider specs to ensure the service provider actually does provide the response the consumer expects.
9
9
 
10
10
  This allows you to test both sides of an integration point using fast unit tests.
11
11
 
12
+ This gem is inspired by the concept of "Consumer driven contracts". See http://martinfowler.com/articles/consumerDrivenContracts.html for more information.
13
+
12
14
  ## Installation
13
15
 
14
16
  Put it in your Gemfile. You know how.
15
17
 
16
18
  ## Usage
17
19
 
18
- ### Consumer project
20
+ ### Service Consumer project
19
21
 
20
22
  #### Configuration
21
23
 
24
+ ```ruby
22
25
  Pact.configure do | config |
23
26
  config.pact_dir = "???" # Optional, default is ./spec/pacts
24
27
  config.log_dir = "???" # Optional, default is ./log
25
- config.logger = "??"
28
+ config.logger = "??" # Optional, defaults to a file logger to the configured log_dir.
26
29
  config.logger.level = Logger::DEBUG #By default this is INFO, bump this up to debug for more detailed logs
30
+ # Optional.
31
+ # The default pactfile_write_mode is "defined?(Rake) ? :overwrite : :update"
32
+ # This allows it to create a clean file when running rake, but only update the executed interactions when running a specific test using "rspec spec/...".
33
+ # This is the recommended setting.
34
+ config.pactfile_write_mode = :ovewrite / :update
27
35
  end
36
+ ```
28
37
 
29
38
  #### Create a Consumer (Driven) Contract
30
39
 
@@ -41,26 +50,23 @@ class SomeServiceClient
41
50
  end
42
51
  end
43
52
 
44
- Pact.configure do | config |
45
- config.consumer do
46
- name 'My Consumer'
53
+ Pact.service_consumer "My Consumer" do
54
+ has_pact_with "My Provider" do
55
+ mock_service :my_service_provider do
56
+ port 1234
57
+ end
47
58
  end
48
59
  end
49
60
 
50
61
  # The following block creates a service on localhost:1234 which will respond to your application's queries
51
- # over HTTP as if it were the real "My Producer" app. It also creats a mock producer object
52
- # which you will use to set up your expectations. The method name to access the mock producer
53
- # will be what ever name you give as the service argument - in this case "my_producer"
62
+ # over HTTP as if it were the real "My Provider" app. It also creats a mock service provider object
63
+ # which you will use to set up your expectations. The method name to access the mock service provider
64
+ # will be what ever name you give as the service argument - in this case "my_service_provider"
54
65
 
55
- Pact.with_producer "My Producer" do
56
- mock_service :my_producer do
57
- port 1234
58
- end
59
- end
60
66
 
61
67
  # Use the :pact => true describe metadata to include all the pact generation functionality in your spec.
62
68
 
63
- describe "a pact with My Producer", :pact => true do
69
+ describe "a pact with My Provider", :pact => true do
64
70
 
65
71
  before do
66
72
  # Configure your client to point to the stub service on localhost using the port you have specified
@@ -68,7 +74,7 @@ describe "a pact with My Producer", :pact => true do
68
74
  end
69
75
 
70
76
  it "returns something when requested" do
71
- my_producer.
77
+ my_service_provider.
72
78
  given("something exists").
73
79
  upon_receiving("a request for something").
74
80
  with({ method: :get, path: '/something' }).
@@ -93,32 +99,26 @@ Logs will be output to the configured log dir that can be useful when diagnosing
93
99
  To run your consumer app as a process during your test (eg for a Capybara test):
94
100
 
95
101
  ```ruby
96
- Pact.configure do | config |
97
- config.consumer do
98
- name 'My Consumer'
99
- app my_consumer_rack_app
100
- port 4321
101
- end
102
+ Pact.service_consumer "My Consumer" do
103
+ app my_consumer_rack_app
104
+ port 4321
105
+ end
102
106
  ```
103
107
 
104
- ### Producer project
108
+ ### Service Provider project
105
109
 
106
- #### Configure your producer rack app
110
+ #### Configure your service provider rack app
107
111
 
108
112
  ```ruby
109
-
110
- Pact.configure do | config |
111
- config.producer do
112
- name "My Producer"
113
- app { MyApp.new }
114
- end
113
+ Pact.service_provider "My Provider" do
114
+ app { MyApp.new }
115
115
  end
116
116
 
117
117
  ```
118
118
 
119
- #### Set up the producer states
119
+ #### Set up the service provider states
120
120
 
121
- Having different producer states allows you to test the same request with different expected responses.
121
+ Having different service provider states allows you to test the same request with different expected responses.
122
122
 
123
123
  For example, some code that creates the pact in a consumer project might look like this:
124
124
 
@@ -136,16 +136,16 @@ my_service.
136
136
  will_respond_with({status: 404, :body => {error: "There is no thing :("} })
137
137
  ```
138
138
 
139
- To define producer states that create the right data for "a thing exists" and "a thing does not exist", write the following in the producer project.
140
- Note that these states have been defined only for the 'My Consumer' consumer by using the Pact.with_consumer block.
139
+ To define service provider states that create the right data for "a thing exists" and "a thing does not exist", write the following in the service provider project.
140
+ Note that these states have been defined only for the 'My Consumer' consumer by using the Pact.provider_states_for block.
141
141
 
142
142
 
143
143
  ```ruby
144
144
  # The consumer name here must match the name of the consumer configured in your consumer project
145
145
  # for it to use these states.
146
146
 
147
- Pact.with_consumer 'My Consumer' do
148
- producer_state "a thing exists" do
147
+ Pact.provider_states_for 'My Consumer' do
148
+ provider_state "a thing exists" do
149
149
  set_up do
150
150
  # Create a thing here using your factory of choice
151
151
  end
@@ -155,7 +155,7 @@ Pact.with_consumer 'My Consumer' do
155
155
  end
156
156
  end
157
157
 
158
- producer_state "a thing does not exist" do
158
+ provider_state "a thing does not exist" do
159
159
  set_up do
160
160
  # Well, probably not much to do here, but you get the picture.
161
161
  end
@@ -164,17 +164,17 @@ end
164
164
 
165
165
  ```
166
166
 
167
- If a state should be used for all consumers, the top level Pact.with_consumer can be skipped, and a global Pact.producer_state can be defined on its own.
167
+ If a state should be used for all consumers, the top level Pact.with_consumer can be skipped, and a global Pact.provider_state can be defined on its own.
168
168
 
169
- #### Create a rake task to verify that the producer honours the pact
169
+ #### Create a rake task to verify that the service provider honours the pact
170
170
 
171
- You'll need to create one or more pact:verify:xxx tasks, that allow the currently checked out producer to be tested against other versions of its consumers - most importantly, head and production.
171
+ You'll need to create one or more pact:verify:xxx tasks, that allow the currently checked out service provider to be tested against other versions of its consumers - most importantly, head and production.
172
172
 
173
173
  Here is an example pact:verify:head task, pointing the the pact file for "some_consumer", found in the build artifacts of the latest successful build of "MY-CONSUMER" project.
174
174
 
175
175
  ```ruby
176
176
  Pact::VerificationTask.new(:head) do | pact |
177
- pact.uri 'http://our_build_server/MY-CONSUMER-BUILD/latestSuccessful/artifact/Pacts/some_consumer-this_producer.json',
177
+ pact.uri 'http://our_build_server/MY-CONSUMER-BUILD/latestSuccessful/artifact/Pacts/some_consumer-this_service provider.json',
178
178
  support_file: './spec/consumers/pact_helper'
179
179
  end
180
180
  ```
@@ -182,20 +182,18 @@ end
182
182
  ```ruby
183
183
  # Ideally we'd like to be able to create a production task like this, but firewalls are making this tricky right now.
184
184
  Pact::VerificationTask.new(:production) do | pact |
185
- pact.uri 'http://our_prod_server/pacts/some_consumer-this_producer.json',
186
- support_file: './spec/consumers/pact_helper', consumer: 'some_consumer'
185
+ pact.uri 'http://our_prod_server/pacts/some_consumer-this_service_provider.json',
186
+ support_file: './spec/consumers/pact_helper'
187
187
  end
188
188
  ```
189
189
 
190
190
  The pact.uri may be a local file system path or a remote URL.
191
191
 
192
- The consumer is optional, and specifies which consumer namespace to use when looking up the producer states, if consumer namespaces have been used.
193
-
194
192
  The support_file should include the code that makes your rack app available for the rack testing framework, and should load all its dependencies (eg include spec_helper)
195
193
 
196
- Multiple pact.uri may be defined in the same rake task if a producer has more than one consumer.
194
+ Multiple pact.uri may be defined in the same rake task if a service provider has more than one consumer.
197
195
 
198
- #### Verify that the producer honours the pact
196
+ #### Verify that the service provider honours the pact
199
197
 
200
198
  rake pact:verify:head
201
199
  rake pact:verify # will run all verify tasks
@@ -212,18 +210,19 @@ when diagnosing issues with pacts.
212
210
  ## TODO
213
211
 
214
212
  Short term:
215
- - Rename ConsumerContract to ConsumerContract (Done)
213
+ - Rename Pact to ConsumerContract (Done)
216
214
  - Simplify set up for consumer (Done)
217
215
  - Move server spawning into to the "at" method (Done)
218
216
  - automatically register before and after hooks in consumer (Done)
219
- - Provide before and after hooks and a place to define the app for Pact configuration in producer (remove Rspc from interface of Pact setup) (Done)
217
+ - Provide before and after hooks and a place to define the app for Pact configuration in service provider (remove Rspc from interface of Pact setup) (Done)
220
218
  - Set_up for state
221
219
  - Tear_down for state
222
220
  - Before hook for all
223
221
  - After hook for all
224
- - Make producer state lookup try consumer defined state first, then fall back to global one (Done)
225
- - Put producer and consumer name into pact file (Done)
222
+ - Make service provider state lookup try consumer defined state first, then fall back to global one (Done)
223
+ - Put service provider and consumer name into pact file (Done)
226
224
  - Remove consumer name from the rake task, as it should now be able to be determined from the pact file. (Done)
225
+ - Provide more flexible matching (eg the keys should match, and the classes of the values should match, but the values of each key do not need to be equal). This is to make the pact verification less brittle.
227
226
 
228
227
  Long term:
229
228
  - Decouple Rspec from Pact and make rspec-pact gem for easy integration
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+ source 'http://rea-rubygems/'
3
+
4
+ gem 'bundler', '~> 1.3.0'
5
+
6
+ group :development, :test do
7
+ gem 'rspec'
8
+ gem 'pact'
9
+ gem 'pry'
10
+ end
11
+
12
+ gem 'rake'
13
+ gem 'rack', '~>1.5.2'
14
+ gem 'json', '~>1.6.8'
15
+ gem 'httparty'
@@ -0,0 +1,77 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ remote: http://rea-rubygems/
4
+ specs:
5
+ awesome_print (1.1.0)
6
+ capybara (2.1.0)
7
+ mime-types (>= 1.16)
8
+ nokogiri (>= 1.3.3)
9
+ rack (>= 1.0.0)
10
+ rack-test (>= 0.5.4)
11
+ xpath (~> 2.0)
12
+ coderay (1.0.9)
13
+ daemons (1.1.9)
14
+ diff-lcs (1.2.4)
15
+ eventmachine (1.0.3)
16
+ find_a_port (1.0.1)
17
+ hashie (2.0.5)
18
+ httparty (0.11.0)
19
+ multi_json (~> 1.0)
20
+ multi_xml (>= 0.5.2)
21
+ json (1.6.8)
22
+ method_source (0.8.2)
23
+ mime-types (1.24)
24
+ mini_portile (0.5.1)
25
+ multi_json (1.7.9)
26
+ multi_xml (0.5.5)
27
+ nokogiri (1.6.0)
28
+ mini_portile (~> 0.5.0)
29
+ pact (0.1.32)
30
+ awesome_print (~> 1.1.0)
31
+ capybara (~> 2.1.0)
32
+ find_a_port (~> 1.0.1)
33
+ hashie (~> 2.0.5)
34
+ json
35
+ rack-test (~> 0.6.2)
36
+ randexp (~> 0.1.7)
37
+ rspec (~> 2.12)
38
+ thin
39
+ thor
40
+ pry (0.9.12.2)
41
+ coderay (~> 1.0.5)
42
+ method_source (~> 0.8)
43
+ slop (~> 3.4)
44
+ rack (1.5.2)
45
+ rack-test (0.6.2)
46
+ rack (>= 1.0)
47
+ rake (10.1.0)
48
+ randexp (0.1.7)
49
+ rspec (2.14.1)
50
+ rspec-core (~> 2.14.0)
51
+ rspec-expectations (~> 2.14.0)
52
+ rspec-mocks (~> 2.14.0)
53
+ rspec-core (2.14.5)
54
+ rspec-expectations (2.14.2)
55
+ diff-lcs (>= 1.1.3, < 2.0)
56
+ rspec-mocks (2.14.3)
57
+ slop (3.4.6)
58
+ thin (1.5.1)
59
+ daemons (>= 1.0.9)
60
+ eventmachine (>= 0.12.6)
61
+ rack (>= 1.0.0)
62
+ thor (0.18.1)
63
+ xpath (2.0.0)
64
+ nokogiri (~> 1.3)
65
+
66
+ PLATFORMS
67
+ ruby
68
+
69
+ DEPENDENCIES
70
+ bundler (~> 1.3.0)
71
+ httparty
72
+ json (~> 1.6.8)
73
+ pact
74
+ pry
75
+ rack (~> 1.5.2)
76
+ rake
77
+ rspec
@@ -0,0 +1,36 @@
1
+ require 'httparty'
2
+ require 'zoo_app/models/alligator'
3
+
4
+ module ZooApp
5
+ class AnimalServiceClient
6
+
7
+ include HTTParty
8
+ base_uri 'animal-service.com'
9
+
10
+ def self.find_alligators
11
+ response = get("/alligators", :headers => {'Accept' => 'application/json'})
12
+ if response.success?
13
+ parse_body(response).collect do | hash |
14
+ ZooApp::Animals::Alligator.new(hash)
15
+ end
16
+ else
17
+ raise response.body
18
+ end
19
+ end
20
+
21
+ def self.find_alligator_by_name name
22
+ response = get("/alligators/#{name}", :headers => {'Accept' => 'application/json'})
23
+ if response.success?
24
+ ZooApp::Animals::Alligator.new(parse_body(response))
25
+ elsif response.code == 404
26
+ nil
27
+ else
28
+ raise response.body
29
+ end
30
+ end
31
+
32
+ def self.parse_body response
33
+ JSON.parse(response.body, {:symbolize_names => true})
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,15 @@
1
+ module ZooApp
2
+ module Animals
3
+ class Alligator
4
+ attr_reader :name
5
+ def initialize attributes
6
+ @name = attributes[:name]
7
+ end
8
+
9
+ def == other
10
+ other.is_a?(Alligator) && other.name == self.name
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,100 @@
1
+ {
2
+ "producer": {
3
+ "name": "Animal Service"
4
+ },
5
+ "consumer": {
6
+ "name": "Zoo App"
7
+ },
8
+ "interactions": [
9
+ {
10
+ "description": "a request for animals",
11
+ "request": {
12
+ "method": "get",
13
+ "path": "/animals"
14
+ },
15
+ "response": {
16
+ "status": 200,
17
+ "headers": {
18
+ "Content-Type": "application/json"
19
+ },
20
+ "body": {
21
+ "alligators": [
22
+ {
23
+ "name": "Bob"
24
+ }
25
+ ]
26
+ }
27
+ },
28
+ "producer_state": "there are alligators"
29
+ },
30
+ {
31
+ "description": "a request for alligators",
32
+ "request": {
33
+ "method": "get",
34
+ "path": "/alligators",
35
+ "headers": {
36
+ "Accept": "application/json"
37
+ }
38
+ },
39
+ "response": {
40
+ "status": 200,
41
+ "headers": {
42
+ "Content-Type": "application/json"
43
+ },
44
+ "body": [
45
+ {
46
+ "name": "Bob"
47
+ }
48
+ ]
49
+ },
50
+ "producer_state": "there are alligators"
51
+ },
52
+ {
53
+ "description": "a request for alligator Mary",
54
+ "request": {
55
+ "method": "get",
56
+ "path": "/alligators/Mary",
57
+ "headers": {
58
+ "Accept": "application/json"
59
+ }
60
+ },
61
+ "response": {
62
+ "status": 200,
63
+ "headers": {
64
+ "Content-Type": "application/json"
65
+ },
66
+ "body": [
67
+ {
68
+ "name": "Mary"
69
+ }
70
+ ]
71
+ },
72
+ "producer_state": "there is an alligator named Mary"
73
+ },
74
+ {
75
+ "description": "a request for alligators",
76
+ "request": {
77
+ "method": "get",
78
+ "path": "/alligators",
79
+ "headers": {
80
+ "Accept": "application/json"
81
+ }
82
+ },
83
+ "response": {
84
+ "status": 500,
85
+ "headers": {
86
+ "Content-Type": "application/json"
87
+ },
88
+ "body": {
89
+ "error": "Argh!!!"
90
+ }
91
+ },
92
+ "producer_state": "an error has occurred"
93
+ }
94
+ ],
95
+ "metadata": {
96
+ "pact_gem": {
97
+ "version": "0.1.32"
98
+ }
99
+ }
100
+ }
@@ -0,0 +1,92 @@
1
+ require_relative 'pact_helper'
2
+
3
+ module ZooApp
4
+ describe "A pact with Animal Service", :pact => true do
5
+
6
+ before do
7
+ AnimalServiceClient.base_uri 'localhost:1234'
8
+ end
9
+
10
+ describe "a call to get alligators" do
11
+
12
+ context "when valid response is received" do
13
+ before do
14
+ animal_service.
15
+ given("there are alligators").
16
+ upon_receiving("a request for alligators").
17
+ with({ method: :get, path: '/alligators', :headers => {'Accept' => 'application/json'} }).
18
+ will_respond_with({
19
+ status: 200,
20
+ headers: { 'Content-Type' => 'application/json' },
21
+ body: [{:name => 'Bob'}]
22
+ })
23
+ end
24
+
25
+ it "returns a list of alligators" do
26
+ expect(AnimalServiceClient.find_alligators).to eq [ZooApp::Animals::Alligator.new(:name => 'Bob')]
27
+ end
28
+
29
+ end
30
+
31
+ context "when an error response is returned" do
32
+ before do
33
+ animal_service.
34
+ given("an error has occurred").
35
+ upon_receiving("a request for alligators").
36
+ with({ method: :get, path: '/alligators', :headers => {'Accept' => 'application/json'} }).
37
+ will_respond_with({
38
+ status: 500,
39
+ headers: { 'Content-Type' => 'application/json' },
40
+ body: {:error => 'Argh!!!'}
41
+ })
42
+ end
43
+
44
+ it "raises an error" do
45
+ expect{ AnimalServiceClient.find_alligators }.to raise_error /Argh/
46
+ end
47
+
48
+ end
49
+ end
50
+
51
+ describe "a call to get an alligator by name" do
52
+ context "when an alligator by the given name exists" do
53
+
54
+ before do
55
+ animal_service.
56
+ given("there is an alligator named Mary").
57
+ upon_receiving("a request for alligator Mary").
58
+ with({ method: :get, path: '/alligators/Mary', :headers => {'Accept' => 'application/json'} }).
59
+ will_respond_with({
60
+ status: 200,
61
+ headers: { 'Content-Type' => 'application/json' },
62
+ body: {:name => 'Mary'}
63
+ })
64
+ end
65
+
66
+ it "returns the alligator" do
67
+ expect(AnimalServiceClient.find_alligator_by_name("Mary")).to eq ZooApp::Animals::Alligator.new(:name => 'Mary')
68
+ end
69
+
70
+ end
71
+
72
+ context "when an alligator by the given name does not exist" do
73
+
74
+ before do
75
+ animal_service.
76
+ given("there is an alligator named Mary").
77
+ upon_receiving("a request for alligator Mary").
78
+ with({ method: :get, path: '/alligators/Mary', :headers => {'Accept' => 'application/json'} }).
79
+ will_respond_with({
80
+ status: 404,
81
+ headers: { 'Content-Type' => 'application/json' }
82
+ })
83
+ end
84
+
85
+ it "returns nil" do
86
+ expect(AnimalServiceClient.find_alligator_by_name("Mary")).to be_nil
87
+ end
88
+
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../spec_helper'
2
+ require 'pact/consumer/rspec'
3
+
4
+ Pact.service_consumer 'Zoo App' do
5
+ has_pact_with "Animal Service" do
6
+ service :animal_service do
7
+ port 1234
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,8 @@
1
+ $: << File.expand_path("../../lib", __FILE__)
2
+
3
+ require 'zoo_app/animal_service_client'
4
+
5
+ RSpec.configure do | config |
6
+ config.color = true
7
+ config.formatter = :documentation
8
+ end
@@ -27,6 +27,8 @@ module Pact
27
27
  end
28
28
  end
29
29
 
30
+ alias_method :service_consumer, :consumer
31
+
30
32
  class ConsumerDSL
31
33
 
32
34
  def initialize &block