Breaking up (with) your test suite

Breaking up (with) your test suite

As presented at Ancient City Ruby 2014.

Please send questions & feedback to hello@testdouble.com!

E6c6e133e74c3b83f04d2861deaa1c20?s=128

Justin Searls

April 03, 2014
Tweet

Transcript

  1. 11.

    I get paid for code that works, not for tests,

    so my philosophy is to test as little as possible to reach a given level of confidence. - Kent Beck asdz ty
  2. 16.

    How to cheat on your customers: ae ts 1. Uncritically

    assume your favorite way to write code applies to every situation
  3. 17.

    How to cheat on your customers: ae ts 1. Uncritically

    assume your favorite way to write code applies to every situation 2. There is no #2
  4. 35.
  5. 38.

     !       ! 

      
  6. 39.

     !       ! 

          !  
  7. 40.

     !       ! 

          !           
  8. 41.

     !       ! 

          !               
  9. 42.

     !       ! 

          !                !    
  10. 43.

     !       ! 

          !                !         !
  11. 44.

     !       ! 

          !                !         !     
  12. 45.

     !       ! 

          !                !         !        !! 
  13. 46.

     !       ! 

         !         !      !                   !!  !         !  !           !  
  14. 47.

     !       ! 

         !         !      !                   !!  !         !  !           !   Confidence
  15. 48.

     !       ! 

         !         !      !                   !!       !                   !! 
  16. 49.

     !       ! 

         !         !      !                   !!  Understanding      !                   !! 
  17. 56.

    describe "Panda" do let(:bamboo) { double("bamboo").as_null_object } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do subject.eat! expect(bamboo).to have_received(:munch) end end
  18. 57.

    describe "Panda" do let(:bamboo) { double("bamboo").as_null_object } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do subject.eat! expect(bamboo).to have_received(:munch) end end
  19. 59.

    describe "Panda" do let(:bamboo) { double("bamboo").as_null_object } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do subject.eat! expect(bamboo).to have_received(:munch) end end
  20. 60.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do subject.eat! expect(bamboo).to have_received(:munch) end end
  21. 61.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do allow(bamboo).to receive(:munch) subject.eat! expect(bamboo).to have_received(:munch) end end
  22. 62.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do allow(bamboo).to receive(:munch) subject.eat! expect(bamboo).to have_received(:munch) end ! it "returns bamboo id" do end end
  23. 63.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do allow(bamboo).to receive(:munch) subject.eat! expect(bamboo).to have_received(:munch) end ! it "returns bamboo id" do expect(subject.eat!).to eq(34) end end
  24. 64.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do allow(bamboo).to receive(:munch) subject.eat! expect(bamboo).to have_received(:munch) end ! it "returns bamboo id" do expect(subject.eat!).to eq(34) end end
  25. 66.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do allow(bamboo).to receive(:munch) subject.eat! expect(bamboo).to have_received(:munch) end ! it "returns bamboo id" do expect(subject.eat!).to eq(34) end end
  26. 67.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do allow(bamboo).to receive(:munch) subject.eat! expect(bamboo).to have_received(:munch) end ! it "returns bamboo id" do expect(subject.eat!).to eq(34) end end ? ? ?
  27. 68.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do allow(bamboo).to receive(:munch) subject.eat! expect(bamboo).to have_received(:munch) end ! it "returns bamboo id" do expect(subject.eat!).to eq(34) end end ? ? ?
  28. 69.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do allow(bamboo).to receive(:munch) subject.eat! expect(bamboo).to have_received(:munch) end ! it "returns bamboo id" do expect(subject.eat!).to eq(34) end end ? ? ? Why does this test exist?
  29. 70.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do allow(bamboo).to receive(:munch) subject.eat! expect(bamboo).to have_received(:munch) end ! it "returns bamboo id" do expect(subject.eat!).to eq(34) end end ? ? ? Why does this test exist? What type of test is this?
  30. 71.

    describe "Panda" do let(:bamboo) { Bamboo.find(34) } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do allow(bamboo).to receive(:munch) subject.eat! expect(bamboo).to have_received(:munch) end ! it "returns bamboo id" do expect(subject.eat!).to eq(34) end end ? ? ? Why does this test exist? How should tests be written? What type of test is this?
  31. 78.

    zxc eqr • purpose is hazy • rules are debatable

    • structure is ad hoc Such tests are unclear:
  32. 82.
  33. 83.

    awe voOa Unclear tests must constantly have their: • purpose

    rediscovered • rules renegotiated • structure reorganized
  34. 122.
  35. 124.

    + -

  36. 125.
  37. 126.

    + - router web app #1 web app #2 walrus

    data panda data cage control service
  38. 127.

    + - router walrus data panda data web front- end

    web back- end web app #1 cage control service
  39. 128.

    + - walrus data web backend panda data router Feed

    Zoo Animals Build Feed Plan Provide Meal Fetch Schedule Plan Meal Animal Adapter Compute Portions cage control service Release Food Cage Adapter
  40. 129.

    + - class ProvidesMeal def initialize... ! def provide(plan) @releases_food.release(

    @computes_portion.compute(plan) ) end end provides_meal.rb
  41. 131.

    + - class ProvidesMeal def initialize... ! def provide(plan) @releases_food.release(

    @computes_portion.compute(plan) ) end end provides_meal.rb
  42. 132.

    + - walrus data web backend panda data router Feed

    Zoo Animals Build Feed Plan Provide Meal Fetch Schedule Plan Meal Animal Adapter Compute Portions cage control service Release Food Cage Adapter
  43. 133.

    + - router walrus data panda data web front- end

    web back- end web app #1 cage control service
  44. 134.

    + - router web app #1 web app #2 walrus

    data panda data cage control service
  45. 135.
  46. 136.

    + -

  47. 147.

    + -

  48. 148.
  49. 162.
  50. 164.
  51. 165.
  52. 169.
  53. 171.
  54. 177.
  55. 187.

    Time-box the suite 5 minutes 5 minutes sign-up monthly financials

    process order ad words search daily deals SAFE
  56. 188.

    Time-box the suite 5 minutes 5 minutes sign-up monthly financials

    process order ad words search daily deals ? SAFE
  57. 189.
  58. 197.

     !       ! 

          !                !         !        !!  SAFE
  59. 198.

     !       ! 

          !                !         !        !!  SAFE
  60. 199.

     !       ! 

          !                !         !        !!  SAFE
  61. 200.
  62. 201.

    + - router web app #1 web app #2 walrus

    data panda data cage control service
  63. 202.

    + - router walrus data panda data web front- end

    web back- end web app #1 cage control service
  64. 230.

     !       ! 

          !                !         !        !!  Consumption
  65. 231.

     !       ! 

          !                !         !        !!  Consumption
  66. 232.

     !       ! 

          !                !         !        !!  Consumption
  67. 233.

    + - router walrus data panda data web front- end

    web back- end web app #1 cage control service
  68. 234.

    + - router web app #1 web app #2 walrus

    data panda data cage control service
  69. 235.

    "If my tests fake out WalrusService how can I trust

    that GET /walruses still returns walruses?" xc r
  70. 239.

    Inter-service tests are easy! cd fe 1. Start by not

    writing them 2. Continue to not write them
  71. 240.

    Inter-service tests are easy! cd fe 1. Start by not

    writing them 2. Continue to not write them 3. You're already done. Easy!
  72. 251.
  73. 259.
  74. 261.
  75. 267.
  76. 271.
  77. 273.

     !       ! 

          !                !         !        !!  Contract
  78. 274.

     !       ! 

          !                !         !        !!  Contract
  79. 275.

     !       ! 

          !                !         !        !!  Contract
  80. 276.

    + - router web app #1 web app #2 walrus

    data panda data cage control service
  81. 277.

    + - router walrus data panda data web front- end

    web back- end web app #1 cage control service
  82. 278.

    + - walrus data web backend panda data router Feed

    Zoo Animals Build Feed Plan Provide Meal Fetch Schedule Plan Meal Animal Adapter Compute Portions cage control service Release Food Cage Adapter
  83. 279.

    + - provides_meal.rb class ProvidesMeal def initialize... ! def provide(plan)

    @releases_food.release( @computes_portion.compute(plan) ) end end
  84. 286.

    I wrote about this a few months ago xi x

    (just Google "tdd failure")
  85. 287.
  86. 289.

    I will refute his arguments and utterly destroy his conclusions.

    And then, once I'm done salting the ground where he used to live, ...l tell you why I completely agree with him. - Uncle Bob asdz ty
  87. 290.

    I will refute his arguments and utterly destroy his conclusions.

    And then, once I'm done salting the ground where he used to live, I'll tell you why I completely agree with him. - Uncle Bob asdz ty
  88. 293.

    Discovery of tiny, boring, consistent units that break big, scary

    problems down into small, manageable ones ri gh
  89. 294.
  90. 311.

    Discovery describe FeedsAnimals do Given(:builds_feed_plan) { gimme(BuildsFeedPlan) } Given(:provides_meal) {

    gimme(ProvidesMeal) } ! subject { FeedsAnimals.new(builds_feed_plan, provides_meal) } ! end
  91. 312.

    Discovery describe FeedsAnimals do Given(:builds_feed_plan) { gimme(BuildsFeedPlan) } Given(:provides_meal) {

    gimme(ProvidesMeal) } ! subject { FeedsAnimals.new(builds_feed_plan, provides_meal) } ! describe "#feed" do end end
  92. 313.

    Discovery describe FeedsAnimals do Given(:builds_feed_plan) { gimme(BuildsFeedPlan) } Given(:provides_meal) {

    gimme(ProvidesMeal) } ! subject { FeedsAnimals.new(builds_feed_plan, provides_meal) } ! describe "#feed" do When(:result) { subject.feed(:walrus, :cheese) } end end
  93. 314.

    Discovery describe FeedsAnimals do Given(:builds_feed_plan) { gimme(BuildsFeedPlan) } Given(:provides_meal) {

    gimme(ProvidesMeal) } ! subject { FeedsAnimals.new(builds_feed_plan, provides_meal) } ! describe "#feed" do When(:result) { subject.feed(:walrus, :cheese) } Then { verify(provides_meal).provide(:cheese, :plan) } end end
  94. 315.

    Discovery describe FeedsAnimals do Given(:builds_feed_plan) { gimme(BuildsFeedPlan) } Given(:provides_meal) {

    gimme(ProvidesMeal) } ! subject { FeedsAnimals.new(builds_feed_plan, provides_meal) } ! describe "#feed" do Given { give(builds_feed_plan).build(:walrus) {:plan}} When(:result) { subject.feed(:walrus, :cheese) } Then { verify(provides_meal).provide(:cheese, :plan) } end end
  95. 316.

    Discovery describe FeedsAnimals do Given(:builds_feed_plan) { gimme(BuildsFeedPlan) } Given(:provides_meal) {

    gimme(ProvidesMeal) } ! subject { FeedsAnimals.new(builds_feed_plan, provides_meal) } ! describe "#feed" do Given { give(builds_feed_plan).build(:walrus) {:plan}} When(:result) { subject.feed(:walrus, :cheese) } Then { verify(provides_meal).provide(:cheese, :plan) } end end
  96. 319.
  97. 324.
  98. 325.
  99. 326.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal ✔️ Compute

    Portions Release Food Build Feed Plan Provide Meal
  100. 327.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal ✔️ Compute

    Portions Release Food ✔️ Build Feed Plan Provide Meal
  101. 328.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal ✔️ Compute

    Portions Release Food ✔️ Build Feed Plan Provide Meal
  102. 329.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal ✔️ Compute

    Portions Release Food ✔️ Build Feed Plan Provide Meal
  103. 330.
  104. 334.
  105. 335.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command
  106. 336.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query
  107. 337.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query Command
  108. 338.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query Query Command
  109. 339.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query Query Logic Command
  110. 340.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query Query Logic Logic Command
  111. 341.

    Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query Query Logic Logic Command Command
  112. 342.
  113. 348.
  114. 351.
  115. 359.

     !       ! 

          !                !         !        !!  Discovery
  116. 360.

     !       ! 

          !                !         !        !!  Discovery
  117. 361.

     !       ! 

          !                !         !        !!  Discovery
  118. 362.

    + - provides_meal.rb class ProvidesMeal def initialize... ! def provide(plan)

    @releases_food.release( @computes_portion.compute(plan) ) end end
  119. 363.

    + - walrus data web backend panda data router Feed

    Zoo Animals Build Feed Plan Provide Meal Fetch Schedule Plan Meal Animal Adapter Compute Portions cage control service Release Food Cage Adapter
  120. 375.

    Wrap 3rd party API calls in adapters that you do

    own uc vt (And mock those adapters instead)
  121. 380.
  122. 383.
  123. 386.
  124. 390.
  125. 393.
  126. 396.
  127. 397.

     !       ! 

          !                !         !        !!  Adapter
  128. 398.

     !       ! 

          !                !         !        !!  Adapter
  129. 399.

     !       ! 

          !                !         !        !!  Adapter
  130. 405.

    Quotation Marks designed by Horacio Bella from the thenounproject.com !

    Happy designed by Michael Hourigan from the thenounproject.com ! Tired designed by Aha-Soft from the thenounproject.com ! Indifference designed by Paul F. from the thenounproject.com ! Mad designed by Aha-Soft from the thenounproject.com ! Sad designed by Simple Icons from the thenounproject.com ! Marker designed by Jeff Seevers from the thenounproject.com ! Database designed by Grant Fisher from the thenounproject.com ! Cloud designed by Thomas Hirter from the thenounproject.com ! Safety Net designed by irene hoffman from the thenounproject.com ! Light Bulb designed by Olivier Guin from the thenounproject.com ! Scale designed by Stephanie Wauters from the thenounproject.com ! Warning designed by Lorena Salagre from the thenounproject.com ! Reload designed by Mateo Zlatar from the thenounproject.com Noun project attribution