Micro Testing Pains

Micro Testing Pains

Micro services are a wonderful thing! Until you try to test them in integration. Do you write a stub for each service? Point them to a test environment? Raise local instances for every dependency? I've tried all these approaches and they are all painful. Can't we can do better?

Yes we can! On this talk we will discuss Consumer Driven Contracts, a better way to deal with integration tests in a micro services environment.

A8725b0691ad37a2554a71652d70831b?s=128

Marcos Castilho da Costa Matos

September 26, 2014
Tweet

Transcript

  1. Micro Testing PAINS 1

  2. Marcos Matos @marcosccm 2

  3. ThoughtWorks 3

  4. Disclaimer ! The author of this document actually likes micro

    services 4
  5. The mythical Monolith 5

  6. A billion* lines codebase that does all the things !

    (actual number may vary) 6
  7. probably not a good idea 7

  8. the current popular way of escaping that is… 8

  9. Micro Services 9

  10. A small codebases with a single well defined functionality (the

    Unix Way) 10
  11. Those services usually communicate through a restish interface 11

  12. Single Responsibility Principle applied to Service Oriented Architecture (SRPSOA for

    short) 12
  13. 13 The MonoRail

  14. 14 Many micro services

  15. Easily replaceable Technology decoupled Simple to understand Natural workstream separation

  16. With these little bundles of joy you eliminate all complexity

    16
  17. Right!? 17

  18. Of course not! 18

  19. Conservation of energy complexity principle ! The total complexity in

    a system remains the same 19 Some smart guys
  20. simple services complex ecosystem 20

  21. Deploying Performance Security Monitoring 21

  22. Different teams Different tech stacks The famous Conway’s Clusterfuck 22

  23. and of course… 23

  24. Acceptance Tests! integration tests, customer tests, coffee break tests, for

    the love of god get green tests 24
  25. How to make sure a service works well with its

    siblings? 25
  26. Tests are only as good as their failure messages 26

  27. expected to find element "#item" is not helpful 27

  28. How to be sure you are not ruining someone else’s

    day? 28
  29. Idea #1 ! Run all the services in your dev

    box! 29
  30. Idea #2 ! Run your tests against a shared environment

    30
  31. Idea #3 ! Stub all the dependencies 31

  32. Idea #4 ! VCR all the things! 32

  33. Let me tell you a sad story :( 33

  34. Idea #5 ! Run your integrated tests in isolation 34

  35. Idea #5 ! This makes no sense! 35

  36. Idea #5 ! Isolate your tests with executable contracts 36

  37. Contract ! The subset of functionality a service needs from

    another service 37
  38. 38 GET /users/marcos a request { name: “marcos”, age: 28

    } a response A simple contract
  39. 39 GET /users/:username a request { name: String, age: Integer

    } a response The important bit is the structure, not the data
  40. 40 service A uses some functionality from service B Consumer

    Producer A B
  41. 41 So you write a contract for that Consumer Producer

    Shared Contract A B
  42. The consumer run its tests against the contract Provider While

    the contract validates itself against the provider Consumer Integrated Tests A Contract Validation B
  43. Looks like a Stub… 43

  44. You could call them declarative, self validating stubs 44

  45. Isolated and integrated tests (paradoxes are fun) 45

  46. There is a gem for that! 46

  47. Pacto Contract Testing for Ruby https://github.com/thoughtworks/pacto 47

  48. For Pacto, contracts are defined as json schema files 48

  49. 49 {! "name": “Get User By Name",! "request": {! "headers":

    {! "Content-Type": "application/json"! },! "http_method": "get",! "path": “/user/:username",! },! "response": {! "status": 201,! "properties": {! "email": {! "type": "string"! }! }! }! } A Pacto Contract
  50. 50 require 'pacto'! require 'pacto/spec'! require 'faraday'! ! before do!

    ! cts = Pacto.load_contracts('contracts', 'http://localhost:5000')! ! cts.stub_providers! end! ! describe 'Isolated testes' do! it 'are awesome' do! conn = Faraday.new(url: 'http://localhost:5000')! response = conn.get '/user/marcosccm'! ! ! expect(response["email"]).to_not be_nil! end ! end Stubbing producers
  51. 51 require 'pacto'! ! cts = Pacto.load_contracts('contracts', 'http://localhost:5000')! cts.simulate_consumers Validating

    producers
  52. 52 Precise error messages! Investigation:! Request: #<Pacto::PactoRequest:0x007fc28dd5c508>! Contract: contracts/get_user_by_name.json! Citations:

    ! ! ! The property '#/name' of type string did not match ! the following type: array ! in schema contracts/get_user_by_name.json
  53. with contracts in a place, you move to the next

    level 53
  54. Consumer Driven Contracts! 54

  55. 55 service A needs some functionality Consumer A

  56. 56 Service A team writes a contract Consumer Draft Contract

    A
  57. 57 Service A and B teams discuss Consumer Producer Contract

    Negotiation A B
  58. Service A evolves it’s features using the contract While service

    B uses the contract to validate the development of the feature Consumer Provider B A Parallel Development
  59. Consumers Provider A B C D A Provider knows exactly

    how it’s functionality is used
  60. Consumer Providers A B C D A Consumer knows precisely

    when one of it’s dependencies is broken
  61. Put the focus back on the consumers 61

  62. Contracts as a communication tool 62

  63. Recap 63

  64. Micro Services are amazing 64

  65. But they bring a lot of challenges 65

  66. Test in isolation with Executable Contracts 66

  67. Use CDCs to evolve your services 67

  68. Wanna know more? ! Ian Robinson on Consumer Driven Contracts

    http://iansrobinson.com/2008/03/27/a-contract-vocabulary-part-1 ! Martin Fowler on Micro Services http://martinfowler.com/articles/microservices.html http://martinfowler.com/bliki/MicroservicePrerequisites.html ! Pacto’s Aussie Brother https://github.com/realestate-com-au/pact 68
  69. obrigado! 69

  70. discussion time! 70