pact 1.1.0.rc2 → 1.1.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/CHANGELOG.md +46 -1
- data/Gemfile.lock +6 -4
- data/README.md +40 -186
- data/Rakefile +1 -1
- data/documentation/README.md +10 -0
- data/documentation/best-practices.md +33 -0
- data/documentation/configuration.md +166 -0
- data/documentation/diff_formatter_embedded.png +0 -0
- data/documentation/diff_formatter_list.png +0 -0
- data/documentation/diff_formatter_unix.png +0 -0
- data/documentation/faq.md +36 -6
- data/documentation/provider-states.md +173 -0
- data/documentation/raq.md +4 -4
- data/documentation/terminology.md +2 -2
- data/example/animal-service/Gemfile.lock +6 -9
- data/example/animal-service/Rakefile +2 -0
- data/example/animal-service/db/animal_db.sqlite3 +0 -0
- data/example/animal-service/lib/animal_service/animal_repository.rb +1 -5
- data/example/animal-service/lib/animal_service/api.rb +1 -1
- data/example/animal-service/spec/service_consumers/pact_helper.rb +7 -10
- data/example/animal-service/spec/service_consumers/provider_states_for_zoo_app.rb +5 -1
- data/example/zoo-app/Gemfile.lock +6 -9
- data/example/zoo-app/Rakefile +5 -0
- data/example/zoo-app/doc/markdown/README.md +3 -0
- data/example/zoo-app/doc/markdown/Zoo App - Animal Service.md +75 -0
- data/example/zoo-app/lib/zoo_app/animal_service_client.rb +2 -2
- data/example/zoo-app/spec/pacts/zoo_app-animal_service.json +1 -1
- data/example/zoo-app/spec/service_providers/animal_service_client_spec.rb +29 -34
- data/example/zoo-app/spec/service_providers/pact_helper.rb +4 -0
- data/lib/pact/configuration.rb +49 -1
- data/lib/pact/consumer/configuration.rb +4 -172
- data/lib/pact/consumer/configuration/configuration_extensions.rb +15 -0
- data/lib/pact/consumer/configuration/dsl.rb +12 -0
- data/lib/pact/consumer/configuration/mock_service.rb +89 -0
- data/lib/pact/consumer/configuration/service_consumer.rb +51 -0
- data/lib/pact/consumer/configuration/service_provider.rb +40 -0
- data/lib/pact/consumer/mock_service/interaction_mismatch.rb +3 -3
- data/lib/pact/consumer/mock_service/interaction_post.rb +2 -2
- data/lib/pact/consumer/mock_service/interaction_replay.rb +3 -4
- data/lib/pact/consumer/mock_service/verification_get.rb +32 -13
- data/lib/pact/consumer/rspec.rb +2 -4
- data/lib/pact/consumer/spec_hooks.rb +3 -1
- data/lib/pact/consumer_contract/consumer_contract.rb +1 -1
- data/lib/pact/consumer_contract/interaction.rb +1 -1
- data/lib/pact/doc/doc_file.rb +40 -0
- data/lib/pact/doc/generate.rb +11 -0
- data/lib/pact/doc/generator.rb +81 -0
- data/lib/pact/doc/interaction_view_model.rb +113 -0
- data/lib/pact/doc/markdown/generator.rb +26 -0
- data/lib/pact/doc/markdown/index_renderer.rb +41 -0
- data/lib/pact/doc/markdown/interaction.erb +14 -0
- data/lib/pact/doc/markdown/interaction_renderer.rb +38 -0
- data/lib/pact/doc/markdown/interactions_renderer.rb +56 -0
- data/lib/pact/doc/sort_interactions.rb +17 -0
- data/lib/pact/matchers/actual_type.rb +16 -0
- data/lib/pact/matchers/base_difference.rb +37 -0
- data/lib/pact/matchers/differ.rb +150 -0
- data/lib/pact/matchers/difference.rb +5 -30
- data/lib/pact/matchers/difference_indicator.rb +26 -0
- data/lib/pact/matchers/embedded_diff_formatter.rb +62 -0
- data/lib/pact/matchers/expected_type.rb +35 -0
- data/lib/pact/matchers/index_not_found.rb +3 -12
- data/lib/pact/matchers/{diff_decorator.rb → list_diff_formatter.rb} +28 -11
- data/lib/pact/matchers/matchers.rb +35 -39
- data/lib/pact/matchers/no_diff_indicator.rb +18 -0
- data/lib/pact/matchers/regexp_difference.rb +13 -0
- data/lib/pact/matchers/type_difference.rb +16 -0
- data/lib/pact/matchers/unexpected_index.rb +3 -13
- data/lib/pact/matchers/unexpected_key.rb +3 -12
- data/lib/pact/matchers/{plus_minus_diff_decorator.rb → unix_diff_formatter.rb} +22 -7
- data/lib/pact/provider/configuration.rb +5 -178
- data/lib/pact/provider/configuration/configuration_extension.rb +58 -0
- data/lib/pact/provider/configuration/dsl.rb +13 -0
- data/lib/pact/provider/configuration/pact_verification.rb +46 -0
- data/lib/pact/provider/configuration/service_provider_config.rb +16 -0
- data/lib/pact/provider/configuration/service_provider_dsl.rb +54 -0
- data/lib/pact/provider/matchers.rb +21 -13
- data/lib/pact/provider/matchers/messages.rb +43 -0
- data/lib/pact/provider/pact_spec_runner.rb +8 -0
- data/lib/pact/provider/rspec.rb +1 -1
- data/lib/pact/provider/rspec/formatter.rb +9 -7
- data/lib/pact/{consumer_contract → shared}/active_support_support.rb +4 -0
- data/lib/pact/shared/jruby_support.rb +18 -0
- data/lib/pact/shared/key_not_found.rb +3 -16
- data/lib/pact/shared/request.rb +5 -5
- data/lib/pact/term.rb +2 -2
- data/lib/pact/version.rb +1 -1
- data/pact.gemspec +2 -2
- data/spec/integration/pact/provider_configuration_spec.rb +2 -1
- data/spec/lib/pact/configuration_spec.rb +73 -0
- data/spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb +21 -3
- data/spec/lib/pact/consumer/mock_service/verification_get_spec.rb +134 -0
- data/spec/lib/pact/consumer/request_spec.rb +1 -1
- data/spec/lib/pact/consumer_contract/active_support_support_spec.rb +1 -1
- data/spec/lib/pact/doc/generator_spec.rb +69 -0
- data/spec/lib/pact/doc/interaction_view_model_spec.rb +112 -0
- data/spec/lib/pact/doc/markdown/index_renderer_spec.rb +29 -0
- data/spec/lib/pact/doc/markdown/interactions_renderer_spec.rb +29 -0
- data/spec/lib/pact/matchers/differ_spec.rb +214 -0
- data/spec/lib/pact/matchers/difference_spec.rb +2 -12
- data/spec/lib/pact/matchers/embedded_diff_formatter_spec.rb +77 -0
- data/spec/lib/pact/matchers/index_not_found_spec.rb +21 -0
- data/spec/lib/pact/matchers/list_diff_formatter_spec.rb +114 -0
- data/spec/lib/pact/matchers/matchers_spec.rb +38 -22
- data/spec/lib/pact/matchers/regexp_difference_spec.rb +20 -0
- data/spec/lib/pact/matchers/type_difference_spec.rb +34 -0
- data/spec/lib/pact/matchers/unexpected_index_spec.rb +20 -0
- data/spec/lib/pact/matchers/unexpected_key_spec.rb +20 -0
- data/spec/lib/pact/matchers/{plus_minus_diff_decorator_spec.rb → unix_diff_formatter_spec.rb} +35 -6
- data/spec/lib/pact/provider/configuration/configuration_extension_spec.rb +30 -0
- data/spec/lib/pact/provider/configuration/pact_verification_spec.rb +43 -0
- data/spec/lib/pact/provider/configuration/service_provider_config_spec.rb +21 -0
- data/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb +92 -0
- data/spec/lib/pact/provider/configuration_spec.rb +7 -150
- data/spec/lib/pact/provider/matchers/messages_spec.rb +104 -0
- data/spec/lib/pact/provider/rspec/formatter_spec.rb +56 -0
- data/spec/lib/pact/shared/key_not_found_spec.rb +20 -0
- data/spec/lib/pact/shared/request_spec.rb +28 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/standalone/consumer_fail_test.rb +54 -0
- data/spec/standalone/consumer_pass_test.rb +50 -0
- data/spec/support/generated_index.md +4 -0
- data/spec/support/generated_markdown.md +55 -0
- data/spec/support/interaction_view_model.json +63 -0
- data/spec/support/markdown_pact.json +48 -0
- data/spec/support/pact_helper.rb +2 -1
- data/spec/support/spec_support.rb +7 -0
- data/spec/support/test_app_fail.json +11 -2
- data/tasks/pact-test.rake +9 -0
- metadata +113 -20
- data/example/animal-service/db/animals_db.sqlite3 +0 -0
- data/lib/pact/consumer/rspec/full_example_description.rb +0 -28
- data/lib/pact/matchers/nested_json_diff_decorator.rb +0 -53
- data/spec/lib/pact/matchers/diff_decorator_spec.rb +0 -80
- data/spec/lib/pact/matchers/nested_json_diff_decorator_spec.rb +0 -48
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,51 @@
|
|
1
1
|
Do this to generate your change history
|
2
2
|
|
3
|
-
git log --
|
3
|
+
git log --pretty=format:' * %h - %s (%an, %ad)'
|
4
|
+
|
5
|
+
### 1.1.0.rc3 (28 April 2014)
|
6
|
+
|
7
|
+
* 41fa409 - Cleaned up consumer after spec failure message (Beth, Sun Apr 27 22:18:03 2014 +1000)
|
8
|
+
* 8593fa9 - Updated zoo-app example (Beth, Sun Apr 27 20:54:51 2014 +1000)
|
9
|
+
* 716e3a8 - Added standalone consumer spec and spec for VerificationGet (Beth, Thu Apr 24 10:15:17 2014 +1000)
|
10
|
+
* c0f9bc6 - Copied RSpec::Expectations::Differ to Pact::Matchers::Differ - safer than trying to override behaviour (Beth, Thu Apr 24 09:17:58 2014 +
|
11
|
+
* 0eeb032 - Changing default diff_formatter to unix (Beth, Thu Apr 24 08:19:15 2014 +1000)
|
12
|
+
* ace5d4d - Update README.md (bethesque, Wed Apr 23 20:59:24 2014 +1000)
|
13
|
+
* 24efef6 - Update configuration.md (bethesque, Wed Apr 23 20:51:00 2014 +1000)
|
14
|
+
* 2d862b7 - Update best-practices.md (bethesque, Wed Apr 23 07:33:01 2014 +1000)
|
15
|
+
* ff8dfd2 - Updated doco (Beth, Tue Apr 22 21:45:17 2014 +1000)
|
16
|
+
* 88e4572 - Moving best practices into its own file (Beth, Tue Apr 22 21:28:36 2014 +1000)
|
17
|
+
* 5a3b92c - Moving provider state documentation out of main README into it's own file. (Beth, Tue Apr 22 19:59:48 2014 +1000)
|
18
|
+
* 1d568c4 - Updated configuration documentation (Beth, Tue Apr 22 13:06:47 2014 +1000)
|
19
|
+
* be1412e - Added configuration documentation (Beth, Tue Apr 22 13:04:33 2014 +1000)
|
20
|
+
* 9f9d178 - Added HAL raq (Beth, Tue Apr 22 12:51:42 2014 +1000)
|
21
|
+
* d9b6479 - Renamed ListOfPathsFormatter to ListDiffFormatter (Beth, Tue Apr 22 12:48:57 2014 +1000)
|
22
|
+
* 6b82402 - Renamed NestedJsonDiffFormatter to EmbeddedDiffFormatter (Beth, Tue Apr 22 12:45:50 2014 +1000)
|
23
|
+
* def8afd - Merge branch 'master' into release-1.1.0 (bethesque, Tue Apr 22 09:13:41 2014 +1000)
|
24
|
+
* 789a471 - Added generated docs to zoo-app (bethesque, Tue Apr 15 17:20:08 2014 +1000)
|
25
|
+
* f5da7ab - Improved header match failure message (bethesque, Tue Apr 15 09:39:12 2014 +1000)
|
26
|
+
* 1179489 - Stopped RSpec turning failure message lines that should be white to red (bethesque, Mon Apr 14 21:41:55 2014 +1000)
|
27
|
+
* ddad510 - Added type and regexp matching output to ListOfPathsFormatter (bethesque, Mon Apr 14 13:43:08 2014 +1000)
|
28
|
+
* b007248 - Added class based matching output to plus_and_minus diff formatter (bethesque, Sat Apr 12 21:20:43 2014 +1000)
|
29
|
+
* f7910a1 - Swapped colored for term-ansicolor, as the colored mixins clash with other gems (bethesque, Sat Apr 12 20:37:57 2014 +1000)
|
30
|
+
* 93bfbdb - Fixing failing tests caused by JRuby inserting a blank line between the braces of an empty hash. Moved ActiveSupportSupport into shared
|
31
|
+
* da16f95 - Added after hook to allow customisation of Doc::Generator (bethesque, Sat Apr 12 18:46:04 2014 +1000)
|
32
|
+
* 85a6fe3 - Breaking up configuration files into separate files (bethesque, Sat Apr 12 11:21:56 2014 +1000)
|
33
|
+
* 7515360 - Merge branch 'doc' into release-1.1.0 (bethesque, Sat Apr 12 10:37:51 2014 +1000)
|
34
|
+
* 1200481 - Removed pact_gem key from pact fixtures (bethesque, Wed Apr 9 22:19:02 2014 +1000)
|
35
|
+
* 72d791b - Ordered rendering of keys in markdown (bethesque, Wed Apr 9 22:15:01 2014 +1000)
|
36
|
+
* 000b223 - Hiding headers and body from docs when they are empty (bethesque, Wed Apr 9 21:46:02 2014 +1000)
|
37
|
+
* 7f6ed91 - Changing request key ordering so it makes more sense when reading it (bethesque, Wed Apr 9 21:45:31 2014 +1000)
|
38
|
+
* 65054a8 - Added index rendering (bethesque, Wed Apr 9 19:38:55 2014 +1000)
|
39
|
+
* 9426565 - Refactoring generation code. Fixed rendering of interaction in markdown when ActiveSupport is loaded (bethesque, Wed Apr 9 18:20:53 2014 +100
|
40
|
+
* 73d0dbf - WIP refactoring generator code (bethesque, Wed Apr 9 17:03:14 2014 +1000)
|
41
|
+
* 7d1d07b - WIP tests and refactor doc generator (bethesque, Wed Apr 9 13:36:46 2014 +1000)
|
42
|
+
|
43
|
+
### 1.0.39 (8 April 2014)
|
44
|
+
|
45
|
+
* a034ab6 - Oh ActiveSupport, why??? Fixing to_json for difference indicators (bethesque, Mon Apr 7 17:26:10 2014 +1000)
|
46
|
+
* 1c7fa0d - Update faq.md (bethesque, Thu Apr 3 09:58:02 2014 +1100)
|
47
|
+
* 8cf5b57 - Update README.md (bethesque, Thu Mar 27 13:38:13 2014 +1100)
|
48
|
+
* 1c5fde9 - Preloading app before suite in pact:verify Ensures consistent behaviour between the first before/after each hooks (bethesque, Thu Mar 27 10:0
|
4
49
|
|
5
50
|
### 1.0.38 (24 March 2014)
|
6
51
|
|
data/Gemfile.lock
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pact (1.1.0.
|
4
|
+
pact (1.1.0.rc3)
|
5
5
|
awesome_print (~> 1.1)
|
6
|
-
colored
|
7
6
|
find_a_port (~> 1.0.1)
|
8
7
|
json
|
9
8
|
rack-test (~> 0.6.2)
|
10
9
|
randexp (~> 0.1.7)
|
11
10
|
rspec (~> 2.12)
|
11
|
+
term-ansicolor (~> 1.0)
|
12
12
|
thor
|
13
13
|
webrick
|
14
14
|
|
@@ -25,7 +25,6 @@ GEM
|
|
25
25
|
atomic (1.1.14)
|
26
26
|
awesome_print (1.2.0)
|
27
27
|
coderay (1.0.9)
|
28
|
-
colored (1.2)
|
29
28
|
crack (0.4.1)
|
30
29
|
safe_yaml (~> 0.9.0)
|
31
30
|
diff-lcs (1.2.4)
|
@@ -58,9 +57,12 @@ GEM
|
|
58
57
|
rspec-mocks (2.14.3)
|
59
58
|
safe_yaml (0.9.5)
|
60
59
|
slop (3.4.6)
|
61
|
-
|
60
|
+
term-ansicolor (1.3.0)
|
61
|
+
tins (~> 1.0)
|
62
|
+
thor (0.19.1)
|
62
63
|
thread_safe (0.1.3)
|
63
64
|
atomic
|
65
|
+
tins (1.1.0)
|
64
66
|
tzinfo (0.3.38)
|
65
67
|
webmock (1.9.3)
|
66
68
|
addressable (>= 2.2.7)
|
data/README.md
CHANGED
@@ -14,10 +14,9 @@ Travis CI Status: [![travis-ci.org Build Status](https://travis-ci.org/realestat
|
|
14
14
|
* A service is mocked using an actual process running on a specified port, so javascript clients can be tested as easily as backend clients.
|
15
15
|
* "Provider states" (similar to fixtures) allow the same request to be made with a different expected response.
|
16
16
|
* Consumers specify only the fields they are interested in, allowing a provider to return more fields without breaking the pact. This allows a provider to have a different pact with a different consumer, and know which fields each cares about in a given response.
|
17
|
-
*
|
18
|
-
* The mocked responses are verified to be valid by replaying the interactions against the provider codebase.
|
19
|
-
* Rake verification tasks allow a pacts at one or more URIs to be checked against a given service provider codebase.
|
17
|
+
* Rake tasks allow pacts to be verified against a service provider codebase.
|
20
18
|
* Different versions of a consumer/provider pairs can be easily tested against each other, allowing confidence when deploying new versions of each (see the pact_broker and pact_broker-client gems).
|
19
|
+
* Autogenerated API documentation - need we say more?
|
21
20
|
|
22
21
|
## How does it work?
|
23
22
|
|
@@ -28,14 +27,15 @@ Travis CI Status: [![travis-ci.org Build Status](https://travis-ci.org/realestat
|
|
28
27
|
## Why is developing and testing with pacts better than using integration tests?
|
29
28
|
|
30
29
|
* Faster execution.
|
31
|
-
* No need to manage starting and stopping multiple processes.
|
32
30
|
* Reliable responses from mock service provider reduce likelihood of flakey tests.
|
33
31
|
* Only one component is being tested at a time, making the causes of test failures easier to identify.
|
34
32
|
* Design of service provider is improved by considering first how the data is actually going to be used, rather than how it is most easily retrieved and serialised.
|
33
|
+
* No need to manage starting, stopping and fixture set up for multiple applications during a test run.
|
35
34
|
|
36
|
-
##
|
35
|
+
## Contact
|
37
36
|
|
38
|
-
https://
|
37
|
+
* Twitter: [@pact_up](https://twitter.com/pact_up)
|
38
|
+
* Google users group: https://groups.google.com/forum/#!forum/pact-support
|
39
39
|
|
40
40
|
## Installation
|
41
41
|
|
@@ -47,10 +47,10 @@ Put it in your Gemfile. You know how.
|
|
47
47
|
|
48
48
|
#### 1. Start with you model
|
49
49
|
|
50
|
-
Imagine a model class that looks something like this. The attributes for a
|
50
|
+
Imagine a model class that looks something like this. The attributes for a Something live on a remote server, and will need to be retrieved by an HTTP call.
|
51
51
|
|
52
52
|
```ruby
|
53
|
-
class
|
53
|
+
class Something
|
54
54
|
attr_reader :name
|
55
55
|
|
56
56
|
def initialize name
|
@@ -58,7 +58,7 @@ class SomethingModel
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def == other
|
61
|
-
other.is_a?(
|
61
|
+
other.is_a?(Something) && other.name == name
|
62
62
|
end
|
63
63
|
end
|
64
64
|
```
|
@@ -68,7 +68,6 @@ end
|
|
68
68
|
Imagine a service provider client class that looks something like this.
|
69
69
|
|
70
70
|
```ruby
|
71
|
-
|
72
71
|
class MyServiceProviderClient
|
73
72
|
include HTTParty
|
74
73
|
base_uri 'http://my-service'
|
@@ -77,7 +76,6 @@ class MyServiceProviderClient
|
|
77
76
|
# Yet to be implemented because we're doing Test First Development...
|
78
77
|
end
|
79
78
|
end
|
80
|
-
|
81
79
|
```
|
82
80
|
#### 3. Configure the mock server
|
83
81
|
|
@@ -114,26 +112,23 @@ describe MyServiceProviderClient, :pact => true do
|
|
114
112
|
subject { MyServiceProviderClient.new }
|
115
113
|
|
116
114
|
describe "get_something" do
|
115
|
+
|
117
116
|
before do
|
118
|
-
my_service_provider.
|
119
|
-
|
120
|
-
|
121
|
-
.with( method: :get, path: '/something' )
|
122
|
-
.will_respond_with(
|
117
|
+
my_service_provider.given("something exists").
|
118
|
+
upon_receiving("a request for something").with(method: :get, path: '/something').
|
119
|
+
will_respond_with(
|
123
120
|
status: 200,
|
124
|
-
headers: {
|
125
|
-
body: {name: 'A small something'}
|
126
|
-
)
|
121
|
+
headers: {'Content-Type' => 'application/json'},
|
122
|
+
body: {name: 'A small something'} )
|
127
123
|
end
|
128
124
|
|
129
125
|
it "returns a Something" do
|
130
|
-
expect(subject.get_something).to eq(
|
126
|
+
expect(subject.get_something).to eq(Something.new('A small something'))
|
131
127
|
end
|
132
128
|
|
133
129
|
end
|
134
130
|
|
135
131
|
end
|
136
|
-
|
137
132
|
```
|
138
133
|
|
139
134
|
#### 5. Run the specs
|
@@ -146,39 +141,45 @@ Of course, the above specs will fail because the client method is not implemente
|
|
146
141
|
#### 6. Implement the client methods
|
147
142
|
|
148
143
|
```ruby
|
149
|
-
|
150
144
|
class MyServiceProviderClient
|
151
145
|
include HTTParty
|
152
146
|
base_uri 'http://my-service'
|
153
147
|
|
154
148
|
def get_something
|
155
149
|
name = JSON.parse(self.class.get("/something").body)['name']
|
156
|
-
|
150
|
+
Something.new(name)
|
157
151
|
end
|
158
152
|
end
|
159
|
-
|
160
153
|
```
|
161
154
|
|
162
155
|
#### 7. Run the specs again.
|
163
156
|
|
164
157
|
Green! You now have a pact file that can be used to verify your expectations in the provider project.
|
165
|
-
Now, rinse and repeat for ALL the likely status codes that may be returned (recommend
|
158
|
+
Now, rinse and repeat for ALL the likely status codes that may be returned (we recommend 404, 500 and 401/403 if there is authorisation.)
|
166
159
|
|
167
160
|
### Service Provider project
|
168
161
|
|
169
162
|
#### 1. Create the skeleton API classes
|
170
163
|
|
171
|
-
Create your API class using the framework of your choice
|
164
|
+
Create your API class using the framework of your choice - leave the methods unimplemented, we're doing Test First Develoment, remember?
|
172
165
|
|
173
166
|
#### 2. Tell your provider that it needs to honour the pact file you made earlier
|
174
167
|
|
168
|
+
Require "pact/tasks" in your Rakefile.
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
# In Rakefile
|
172
|
+
require 'pact/tasks'
|
173
|
+
```
|
174
|
+
|
175
175
|
Create a `pact_helper.rb` in your service provider project. The file must be called pact_helper.rb, however there is some flexibility in where it can be stored. The recommended place is `specs/service_consumers/pact_helper.rb`.
|
176
176
|
|
177
|
+
See the [Provider](/documentation.md#provider) section of the Configuration documentation for more information.
|
178
|
+
|
177
179
|
```ruby
|
180
|
+
# In specs/service_consumers/pact_helper.rb
|
181
|
+
|
178
182
|
require 'pact/provider/rspec'
|
179
|
-
# If you wish to use the same spec_helper file as your unit tests, require it here.
|
180
|
-
# Otherwise, you can set up a separate RSpec configuration in this file just for pact:verify.
|
181
|
-
require './spec_helper'
|
182
183
|
|
183
184
|
Pact.service_provider "My Service Provider" do
|
184
185
|
|
@@ -193,14 +194,6 @@ Pact.service_provider "My Service Provider" do
|
|
193
194
|
pact_uri '../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json'
|
194
195
|
end
|
195
196
|
end
|
196
|
-
|
197
|
-
```
|
198
|
-
Require "pact/tasks" in your Rakefile. If the pact gem is in the test/development section of your Gemfile, you may want to put an env check around this so it doesn't load the pact tasks in prod.
|
199
|
-
|
200
|
-
```ruby
|
201
|
-
# In Rakefile
|
202
|
-
|
203
|
-
require 'pact/tasks'
|
204
197
|
```
|
205
198
|
|
206
199
|
#### 3. Run your failing specs
|
@@ -209,11 +202,13 @@ require 'pact/tasks'
|
|
209
202
|
|
210
203
|
Congratulations! You now have a failing spec to develop against.
|
211
204
|
|
212
|
-
|
205
|
+
At this stage, you'll want to be able to run your specs one at a time while you implement each feature. At the bottom of the failed pact:verify output you will see the commands to rerun each failed interaction individually. A command to run just one interaction will look like this:
|
206
|
+
|
207
|
+
$ rake pact:verify PACT_DESCRIPTION="a request for something" PACT_PROVIDER_STATE="something exists"
|
213
208
|
|
214
|
-
|
209
|
+
#### 4. Implement enough to make your first interaction spec pass
|
215
210
|
|
216
|
-
|
211
|
+
Rinse and repeat.
|
217
212
|
|
218
213
|
#### 5. Keep going til you're green
|
219
214
|
|
@@ -221,102 +216,9 @@ Yay! Your provider now honours the pact it has with your consumer. You can now h
|
|
221
216
|
|
222
217
|
### Using provider states
|
223
218
|
|
224
|
-
Provider states allow
|
219
|
+
Provider states allow you to set up data on the provider before the interaction is run, so that it can make a response that matches what the consumer expects. It also allows the consumer to make the same request with different expected responses.
|
225
220
|
|
226
|
-
|
227
|
-
|
228
|
-
```ruby
|
229
|
-
my_service.
|
230
|
-
given("a thing exists").
|
231
|
-
upon_receiving("a request for a thing").
|
232
|
-
with(method: 'get', path: '/thing').
|
233
|
-
will_respond_with(status: 200, :body => {thing: "yay!"} )
|
234
|
-
|
235
|
-
...
|
236
|
-
|
237
|
-
my_service.
|
238
|
-
given("a thing does not exist").
|
239
|
-
upon_receiving("a request for a thing").
|
240
|
-
with(method: 'get', path: '/thing').
|
241
|
-
will_respond_with(status: 404)
|
242
|
-
|
243
|
-
...
|
244
|
-
|
245
|
-
my_service.
|
246
|
-
given("an error occurs while retrieving a thing").
|
247
|
-
upon_receiving("a request for a thing").
|
248
|
-
with(method: 'get', path: '/thing').
|
249
|
-
will_respond_with(status: 500, :body => {message: "An error occurred"}, :headers => { 'Content-Type' => 'application/json'} )
|
250
|
-
```
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
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. (The consumer name here must match the name of the consumer configured in your consumer project for it to correctly find these provider states.)
|
255
|
-
|
256
|
-
|
257
|
-
```ruby
|
258
|
-
# In /spec/service_consumers/provider_states_for_my_service_consumer.rb
|
259
|
-
|
260
|
-
Pact.provider_states_for 'My Service Consumer' do
|
261
|
-
provider_state "a thing exists" do
|
262
|
-
set_up do
|
263
|
-
# Create a thing here using your factory of choice
|
264
|
-
end
|
265
|
-
|
266
|
-
tear_down do
|
267
|
-
# Any tear down steps to clean up your code (or use RSpec.after(:each))
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
provider_state "a thing does not exist" do
|
272
|
-
no_op # If there's nothing to do because the state name is more for documentation purposes, you can use no_op to imply this.
|
273
|
-
end
|
274
|
-
|
275
|
-
provider_state "an error occurs while retrieving a thing" do
|
276
|
-
set_up do
|
277
|
-
ThingRepository.stub(:find).and_raise("An error occurred!")
|
278
|
-
end
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
```
|
283
|
-
|
284
|
-
```ruby
|
285
|
-
# In /spec/service_consumers/pact_helper.rb
|
286
|
-
|
287
|
-
require_relative 'provider_states_for_my_service_consumer.rb'
|
288
|
-
```
|
289
|
-
|
290
|
-
To define code that should run before/after each interaction, regardless of whether a provider state is specified or not:
|
291
|
-
|
292
|
-
```ruby
|
293
|
-
|
294
|
-
Pact.provider_states_for 'My Service Consumer' do
|
295
|
-
|
296
|
-
set_up do
|
297
|
-
# eg. create API user, start database cleaner transaction
|
298
|
-
end
|
299
|
-
|
300
|
-
tear_down do
|
301
|
-
# eg. clean database
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
```
|
306
|
-
|
307
|
-
Or for global set up/tear down for all consumers:
|
308
|
-
|
309
|
-
```ruby
|
310
|
-
Pact.set_up do
|
311
|
-
# eg. start database cleaner transaction
|
312
|
-
# Avoid using the global set up for creating data as it will make your tests brittle.
|
313
|
-
# You don't want changes to one consumer pact to affect another one.
|
314
|
-
end
|
315
|
-
|
316
|
-
Pact.tear_down do
|
317
|
-
# eg. clean database
|
318
|
-
end
|
319
|
-
```
|
221
|
+
Read more about provider states [here](/documentation/provider-states.md).
|
320
222
|
|
321
223
|
### Verifying pacts
|
322
224
|
|
@@ -338,64 +240,18 @@ Pact::VerificationTask.new(:dev) do | pact |
|
|
338
240
|
end
|
339
241
|
```
|
340
242
|
|
341
|
-
|
243
|
+
## Configuration
|
342
244
|
|
343
|
-
|
344
|
-
Pact.configure do | config |
|
345
|
-
config.pact_dir = "???" # Optional, default is ./spec/pacts
|
346
|
-
config.log_dir = "???" # Optional, default is ./log
|
347
|
-
config.logger = "??" # Optional, defaults to a file logger to the configured log_dir.
|
348
|
-
config.logger.level = Logger::DEBUG #By default this is INFO, bump this up to debug for more detailed logs
|
349
|
-
config.pactfile_write_mode = :ovewrite / :update / :smart # Optional. The default pactfile_write_mode is :overwrite. See notes in Advanced section for further information.
|
350
|
-
end
|
351
|
-
```
|
245
|
+
See the [Configuration](/documentation/configuration.md) section of the documentation for options relating to thing like logging, diff formatting, and documentation generation.
|
352
246
|
|
353
247
|
## Pact best practices
|
354
248
|
|
355
|
-
|
356
|
-
|
357
|
-
#### Publish your pacts as artifacts on your CI machine
|
358
|
-
|
359
|
-
This makes the pact available via URL, which your provider build can then use when it runs pact:verify.
|
360
|
-
|
361
|
-
#### Ensure all calls to the provider go through your provider client class
|
362
|
-
|
363
|
-
Do not hand create any HTTP requests in your consumer app or specs. Testing through your provider client class gives you the assurance that your consumer app will be creating exactly the HTTP requests that you think it should.
|
364
|
-
|
365
|
-
#### Use factories to create your expected models
|
366
|
-
|
367
|
-
Sure, you've checked that your client deserialises the HTTP response into the object you expect, but then you need to make sure in your other tests where you stub your client that you're stubbing it with a valid object. The best way to do this is to use factories for all your tests.
|
368
|
-
|
369
|
-
### In your provider project
|
370
|
-
|
371
|
-
#### Use the pact artifact published by your consumer's CI build to verify the provider
|
372
|
-
|
373
|
-
Configure the pact_uri in the Pact.service_provider block with the pact artifact URL of your last successful build. This way you're only verifying green builds. No point verifying a broken one.
|
374
|
-
(Watch this space - pact-broker coming soon, so we don't have to use messy build box artifact URLs)
|
375
|
-
|
376
|
-
#### Add pact:verify to your default rake task
|
377
|
-
|
378
|
-
It should run with all your other tests. If an integration is broken, you want to know about it *before* you check in.
|
379
|
-
|
380
|
-
#### Stub calls to downstream systems
|
381
|
-
|
382
|
-
Consider making a separate pact with the downstream system and using shared fixtures.
|
383
|
-
|
384
|
-
#### Consider carefully whether to use the real database or stub calls
|
385
|
-
|
386
|
-
You may choose not stub your database calls for pact:verify. This can be a good time for you to test your database integration if you have a simple application, however, for a complex one, you might want to carefully choose a point at which to stub calls.
|
249
|
+
As in all things, there are good ways to implement Pacts, and there are not so good ways. Check out the [Best practices](/documentation/best-practices.md) section of the documentation to make sure you're not Pacting it Wrong.
|
387
250
|
|
388
251
|
## Gotchas
|
389
252
|
|
390
253
|
* Be aware when using the app from the config.ru file is used (the default option) that the Rack::Builder.parse_file seems to require files even if they have already been required, so make sure your boot files are idempotent.
|
391
254
|
|
392
|
-
## Advanced
|
393
|
-
|
394
|
-
### Filtering the pact:verify specs
|
395
|
-
|
396
|
-
To execute a subset of the specs when running any of the pact verification tasks, define the environment variables PACT_DESCRIPTION and/or PACT_PROVIDER_STATE.
|
397
|
-
|
398
|
-
$ PACT_DESCRIPTION="a request for something" PACT_PROVIDER_STATE="something exists" rake pact:verify
|
399
255
|
|
400
256
|
See [Frequently Asked Questions](https://github.com/realestate-com-au/pact/blob/master/documentation/faq.md) and [Rarely Asked Questions](https://github.com/realestate-com-au/pact/blob/master/documentation/raq.md) and [Terminology](https://github.com/realestate-com-au/pact/blob/master/documentation/terminology.md) for more information.
|
401
257
|
|
@@ -413,13 +269,11 @@ See [Frequently Asked Questions](https://github.com/realestate-com-au/pact/blob/
|
|
413
269
|
## TODO
|
414
270
|
|
415
271
|
Short term:
|
416
|
-
- FIX EXAMPLE!!!
|
417
272
|
- Support hash of query params
|
418
273
|
|
419
274
|
Long term:
|
420
275
|
- 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.
|
421
276
|
- Add XML support
|
422
|
-
- Improve display of interaction diffs
|
423
277
|
- Decouple Rspec from Pact and make rspec-pact gem for easy integration
|
424
278
|
|
425
279
|
## Contributing
|