The document discusses using consumer-driven contract testing with Pact to test microservices. It outlines the benefits of consumer-driven contracts over traditional integration tests and dictator-driven contracts. It then provides an example of defining expectations between a consumer and provider using Pact, publishing and verifying the Pact contract. The presentation encourages learning more about Pact through its documentation and community resources.
16. 1. Sit in ivory tower and postulate
2. Document perfect API (Swagger, API blueprint etc.)
3. Create said API
4. Publish said document to consumers
5. Repeat steps 1-4
How to: Dictator Driven Contracts
31. Given “User A exists”
When I Receive “a GET request for user A”
With “these headers and query”
Respond with “200 OK”
And “User A’s details in the body”
32. Given “User A does not exist”
When I Receive “a GET request for user A”
Respond with “404 Not Found”
34. // Create a Pact test runner, connecting to local Daemon
// NOTE: I tend to use TestMain(m *testing.M) to set this up!
pact := dsl.Pact{
Port: 6666,
Consumer: "My Consumer",
Provider: "My Provider",
}
// Shuts down Mock Service when done
defer pact.Teardown()
35. // Setup our expected interactions on the Mock Service.
pact.
AddInteraction().
Given("User billy exists").
UponReceiving("A request to login with user 'billy'").
WithRequest(dsl.Request{
Method: "POST",
Path: "/users/login",
Body: loginRequest,
}).
WillRespondWith(dsl.Response{
Status: 200,
Headers: map[string]string{
"Content-Type": "application/json",
},
Body: `
{
"user": {
"name": "billy"
}
}
`,
})
36. // Run the test and verify the interactions.
err := pact.Verify(func() error {
client := Client{
Host: fmt.Sprintf("http://localhost:%d", pact.Server.Port),
}
client.loginHandler(rr, req)
// Expect User to be set on the Client
if client.user == nil {
return errors.New("Expected user not to be nil")
}
return nil
})
if err != nil {
t.Fatalf("Error on Verify: %v", err)
}
// Write pact to file `<pwd>/pacts/my_consumer-my_provider.json`
// NOTE: This also is a good candidate for use in TestMain(m *testing.M)
pact.WritePact()
40. // Verify the Provider from tagged Pact files stored in a Pact Broker
response = pact.VerifyProvider(types.VerifyRequest{
ProviderBaseURL: fmt.Sprintf("http://localhost:%d", providerPort),
BrokerURL: brokerHost,
Tags: []string{"latest", "prod"},
ProviderStatesURL: fmt.Sprintf("http://localhost:%d/states", providerPort),
ProviderStatesSetupURL: fmt.Sprintf("http://localhost:%d/setup", providerPort),
BrokerUsername: os.Getenv("PACT_BROKER_USERNAME"),
BrokerPassword: os.Getenv("PACT_BROKER_PASSWORD"),
})
if response.ExitCode != 0 {
t.Fatalf("Got %d, Want exit code 0", response.ExitCode)
}
41. Verifying a pact between billy and bobby
Given User billy exists
A request to login with user 'billy'
with POST /users/login
returns a response which
Setting up provider state 'User billy exists' for consumer 'billy' using provider state server at
http://localhost:55128/setup
has status code 200
has a matching body
includes headers
"Content-Type" with value "application/json"
Given User billy does not exist
A request to login with user 'billy'
with POST /users/login
returns a response which
Setting up provider state 'User billy does not exist' for consumer 'billy' using provider state server at
http://localhost:55128/setup
has status code 404
includes headers
"Content-Type" with value "application/json"
...
Finished in 0.03042 seconds
7 examples, 0 failures
42. Verifying a pact between billy and bobby
Given User billy exists
A request to login with user 'billy'
with POST /users/login
returns a response which
Setting up provider state 'User billy exists' for consumer 'billy' using provider state server at
http://localhost:55420/setup
has status code 200
has a matching body (FAILED - 1)
includes headers
"Content-Type" with value "application/json"
Failures:
1) Verifying a pact between billy and bobby Given User billy exists A request to login with user 'billy' with POST
/users/login returns a response which has a matching body
Failure/Error: expect(response_body).to match_term expected_response_body, diff_options
Actual: {"user":{"user":"billy"}}
@@ -1,6 +1,5 @@
{
"user": {
- "name": "billy"
}
}
43. Find out more
● Gitbook: docs.pact.io
● Github: pact-foundation/pact-go
● Google users group:
https://groups.google.com/forum/#!forum/pact-support
● Gitter: Join the chat at
https://gitter.im/realestate-com-au/pact
● Twitter: @pact_up
44. Thank you
- @matthewfellows
Given “The presentation is over”
Upon Receiving “A request for an answer”
With “A valid question”
Respond With “A valid answer”