Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Deploy with Confidence!
Deploy faster and safer using Pact
PRESENTED BY Matt Fellows (@matthewfellows)
Everyone is doing microservices
How do you test this?
“Integration tests are a scam”
- JB Rainsberger
Scam, you say? Justify!
Integrated tests are:
● Slow
● Fragile
● Hard to manage
When they fail, you can’t point to the pro...
Scam, you say? Justify!
“But my integration tests run in Docker, why can’t I use
them?”
- People
Scam, you say? Justify!
“Because Maths”
- Me
Branches per box vs test cases required
2 code branches = 128 tests
5 code branches = 78,125 tests
10 code branches = 10M ...
Good tests have the exact opposite properties
Dictator Driven Contracts
1. Sit in ivory tower and postulate
2. Document perfect API (Swagger, API blueprint etc.)
3. Create said API
4. Publish sa...
Dictator Consumer Driven Contracts
Benefits?
You’ll know when you break a consumer
You have a form of documentation
You can test things independently
Pact
www.pact.io
Evolved from combining these two principles
Step 1: Define Consumer expectations
Step 1: Define Consumer expectations
Step 2: Verify expectations on Provider
Start with a consumer test
Given “User A exists”
When I Receive “a GET request for user A”
With “these headers and query”
Respond with “200 OK”
And “...
Given “User A does not exist”
When I Receive “a GET request for user A”
Respond with “404 Not Found”
Example
// Create a Pact test runner, connecting to local Daemon
// NOTE: I tend to use TestMain(m *testing.M) to set this up!
pac...
// Setup our expected interactions on the Mock Service.
pact.
AddInteraction().
Given("User billy exists").
UponReceiving(...
// Run the test and verify the interactions.
err := pact.Verify(func() error {
client := Client{
Host: fmt.Sprintf("http:/...
Next publish your pacts
// Publish the Pacts...
p := dsl.Publisher{}
err := p.Publish(types.PublishRequest{
PactURLs: []string{"../pacts/myconsume...
Then verify your provider
// Verify the Provider from tagged Pact files stored in a Pact Broker
response = pact.VerifyProvider(types.VerifyRequest{
...
Verifying a pact between billy and bobby
Given User billy exists
A request to login with user 'billy'
with POST /users/log...
Verifying a pact between billy and bobby
Given User billy exists
A request to login with user 'billy'
with POST /users/log...
Find out more
● Gitbook: docs.pact.io
● Github: pact-foundation/pact-go
● Google users group:
https://groups.google.com/fo...
Thank you
- @matthewfellows
Given “The presentation is over”
Upon Receiving “A request for an answer”
With “A valid questi...
Deploy with Confidence using Pact Go!
Deploy with Confidence using Pact Go!
Deploy with Confidence using Pact Go!
Deploy with Confidence using Pact Go!
Deploy with Confidence using Pact Go!
Deploy with Confidence using Pact Go!
Deploy with Confidence using Pact Go!
Deploy with Confidence using Pact Go!
Deploy with Confidence using Pact Go!
Upcoming SlideShare
Loading in …5
×

Deploy with Confidence using Pact Go!

579 views

Published on

Deploy faster and safer using Pact (http://pact.io)

Slides from Golang Melbourne Meetup July 2016 (http://www.meetup.com/golang-mel/events/229251263/).

Published in: Technology
  • Be the first to comment

Deploy with Confidence using Pact Go!

  1. 1. Deploy with Confidence! Deploy faster and safer using Pact PRESENTED BY Matt Fellows (@matthewfellows)
  2. 2. Everyone is doing microservices
  3. 3. How do you test this?
  4. 4. “Integration tests are a scam” - JB Rainsberger
  5. 5. Scam, you say? Justify! Integrated tests are: ● Slow ● Fragile ● Hard to manage When they fail, you can’t point to the problem!
  6. 6. Scam, you say? Justify! “But my integration tests run in Docker, why can’t I use them?” - People
  7. 7. Scam, you say? Justify! “Because Maths” - Me
  8. 8. Branches per box vs test cases required 2 code branches = 128 tests 5 code branches = 78,125 tests 10 code branches = 10M tests
  9. 9. Good tests have the exact opposite properties
  10. 10. Dictator Driven Contracts
  11. 11. 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
  12. 12. Dictator Consumer Driven Contracts
  13. 13. Benefits?
  14. 14. You’ll know when you break a consumer
  15. 15. You have a form of documentation
  16. 16. You can test things independently
  17. 17. Pact www.pact.io
  18. 18. Evolved from combining these two principles
  19. 19. Step 1: Define Consumer expectations
  20. 20. Step 1: Define Consumer expectations Step 2: Verify expectations on Provider
  21. 21. Start with a consumer test
  22. 22. 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”
  23. 23. Given “User A does not exist” When I Receive “a GET request for user A” Respond with “404 Not Found”
  24. 24. Example
  25. 25. // 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()
  26. 26. // 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" } } `, })
  27. 27. // 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()
  28. 28. Next publish your pacts
  29. 29. // Publish the Pacts... p := dsl.Publisher{} err := p.Publish(types.PublishRequest{ PactURLs: []string{"../pacts/myconsumer-myprovider.json"}, PactBroker: os.Getenv("PACT_BROKER_HOST"), ConsumerVersion: "1.0.0", Tags: []string{"latest", "production"}, BrokerUsername: os.Getenv("PACT_BROKER_USERNAME"), BrokerPassword: os.Getenv("PACT_BROKER_PASSWORD"), })
  30. 30. Then verify your provider
  31. 31. // 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) }
  32. 32. 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
  33. 33. 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" } }
  34. 34. 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
  35. 35. Thank you - @matthewfellows Given “The presentation is over” Upon Receiving “A request for an answer” With “A valid question” Respond With “A valid answer”

×