Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Breaking up (with) your test suite

Breaking up (with) your test suite

As presented at Ancient City Ruby 2014.

Please send questions & feedback to [email protected]!

Justin Searls

April 03, 2014
Tweet

More Decks by Justin Searls

Other Decks in Programming

Transcript

  1. 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. How to cheat on your customers: ae ts 1. Uncritically

    assume your favorite way to write code applies to every situation
  3. 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.  !       ! 

      
  5.  !       ! 

          !  
  6.  !       ! 

          !           
  7.  !       ! 

          !               
  8.  !       ! 

          !                !    
  9.  !       ! 

          !                !         !
  10.  !       ! 

          !                !         !     
  11.  !       ! 

          !                !         !        !! 
  12.  !       ! 

         !         !      !                   !!  !         !  !           !  
  13.  !       ! 

         !         !      !                   !!  !         !  !           !   Confidence
  14.  !       ! 

         !         !      !                   !!       !                   !! 
  15.  !       ! 

         !         !      !                   !!  Understanding      !                   !! 
  16. 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
  17. 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. 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. 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
  20. 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
  21. 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
  22. 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
  23. 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. 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. 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. 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. 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?
  28. 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?
  29. 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?
  30. zxc eqr • purpose is hazy • rules are debatable

    • structure is ad hoc Such tests are unclear:
  31. awe voOa Unclear tests must constantly have their: • purpose

    rediscovered • rules renegotiated • structure reorganized
  32. + -

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

    data panda data cage control service
  34. + - router walrus data panda data web front- end

    web back- end web app #1 cage control service
  35. + - 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
  36. + - class ProvidesMeal def initialize... ! def provide(plan) @releases_food.release(

    @computes_portion.compute(plan) ) end end provides_meal.rb
  37. + - class ProvidesMeal def initialize... ! def provide(plan) @releases_food.release(

    @computes_portion.compute(plan) ) end end provides_meal.rb
  38. + - 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
  39. + - router walrus data panda data web front- end

    web back- end web app #1 cage control service
  40. + - router web app #1 web app #2 walrus

    data panda data cage control service
  41. + -

  42. + -

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

    process order ad words search daily deals SAFE
  44. Time-box the suite 5 minutes 5 minutes sign-up monthly financials

    process order ad words search daily deals ? SAFE
  45.  !       ! 

          !                !         !        !!  SAFE
  46.  !       ! 

          !                !         !        !!  SAFE
  47.  !       ! 

          !                !         !        !!  SAFE
  48. + - router web app #1 web app #2 walrus

    data panda data cage control service
  49. + - router walrus data panda data web front- end

    web back- end web app #1 cage control service
  50.  !       ! 

          !                !         !        !!  Consumption
  51.  !       ! 

          !                !         !        !!  Consumption
  52.  !       ! 

          !                !         !        !!  Consumption
  53. + - router walrus data panda data web front- end

    web back- end web app #1 cage control service
  54. + - router web app #1 web app #2 walrus

    data panda data cage control service
  55. "If my tests fake out WalrusService how can I trust

    that GET /walruses still returns walruses?" xc r
  56. Inter-service tests are easy! cd fe 1. Start by not

    writing them 2. Continue to not write them
  57. 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!
  58.  !       ! 

          !                !         !        !!  Contract
  59.  !       ! 

          !                !         !        !!  Contract
  60.  !       ! 

          !                !         !        !!  Contract
  61. + - router web app #1 web app #2 walrus

    data panda data cage control service
  62. + - router walrus data panda data web front- end

    web back- end web app #1 cage control service
  63. + - 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
  64. + - provides_meal.rb class ProvidesMeal def initialize... ! def provide(plan)

    @releases_food.release( @computes_portion.compute(plan) ) end end
  65. I wrote about this a few months ago xi x

    (just Google "tdd failure")
  66. 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
  67. 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
  68. Discovery of tiny, boring, consistent units that break big, scary

    problems down into small, manageable ones ri gh
  69. Discovery describe FeedsAnimals do Given(:builds_feed_plan) { gimme(BuildsFeedPlan) } Given(:provides_meal) {

    gimme(ProvidesMeal) } ! subject { FeedsAnimals.new(builds_feed_plan, provides_meal) } ! end
  70. 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
  71. 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
  72. 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
  73. 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
  74. 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
  75. Discovery Feed Zoo Animals Fetch Schedule Plan Meal ✔️ Compute

    Portions Release Food Build Feed Plan Provide Meal
  76. Discovery Feed Zoo Animals Fetch Schedule Plan Meal ✔️ Compute

    Portions Release Food ✔️ Build Feed Plan Provide Meal
  77. Discovery Feed Zoo Animals Fetch Schedule Plan Meal ✔️ Compute

    Portions Release Food ✔️ Build Feed Plan Provide Meal
  78. Discovery Feed Zoo Animals Fetch Schedule Plan Meal ✔️ Compute

    Portions Release Food ✔️ Build Feed Plan Provide Meal
  79. Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command
  80. Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query
  81. Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query Command
  82. Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query Query Command
  83. Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query Query Logic Command
  84. Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query Query Logic Logic Command
  85. Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

    Release Food Build Feed Plan Provide Meal Command Query Query Logic Logic Command Command
  86.  !       ! 

          !                !         !        !!  Discovery
  87.  !       ! 

          !                !         !        !!  Discovery
  88.  !       ! 

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

    @releases_food.release( @computes_portion.compute(plan) ) end end
  90. + - 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
  91. Wrap 3rd party API calls in adapters that you do

    own uc vt (And mock those adapters instead)
  92.  !       ! 

          !                !         !        !!  Adapter
  93.  !       ! 

          !                !         !        !!  Adapter
  94.  !       ! 

          !                !         !        !!  Adapter
  95. 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