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. Breaking up (with) your test suite poa asd 

  2. My name is Justin Searls Please tweet me @searls &

    Say hello@testdouble.com
  3. Any questions?  Tweet @searls during the talk Favorite question

    gets a book!
  4. Any questions?  Tweet @searls during the talk Favorite question

    gets a book!
  5. This talk is about z aPPOOIU

  6. This talk is about z aPPOOIU relationships

  7. I my customers ias al

  8. I coding zffrttyu z

  9. I testing aske zc

  10. We don't test for testing's sake rRth asd

  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
  12. We don't code for code's sake, either mmmmznxdfr lr

  13. Writing code is a costly way to solve problems oiz

    eu
  14. Too often, we cheat on our customers with our code

    c d aoiey
  15. How to cheat on your customers: ae ts

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

    assume your favorite way to write code applies to every situation
  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
  18. evh zc Cargo-culting as a service

  19. We must challenge our biases in each new context to

    grow fh ywe
  20. iO ZOe infatuation

  21. xmt iRosXc Remember TATFT?

  22. TDD literally rescued me from the pit of despair.

  23. lzxcm zxcmlzcl lzxckz zxczc zxjcozcjoe AOO asodjaosd encz caosdjojo jojo

    6 months later ~ ~
  24. Why does every refactor break 6 tests?!

  25. Why does the build take nine hours to run?!

  26. Why are people mocking methods on the object they're testing?!

  27. Why can't we get anything done anymore?

  28. asodo zoxjcz aoo ueue yyyz cxjk zxcczx and eventually ~

    ~
  29. the break-up

  30. the break-up

  31. $ the break-up

  32. $ the break-up rm -rf spec features

  33. jn poi introspection

  34. qwer bvt Why test?

  35. None
  36.   !  

  37.  !       ! 

    
  38.  !       ! 

      
  39.  !       ! 

          !  
  40.  !       ! 

          !           
  41.  !       ! 

          !               
  42.  !       ! 

          !                !    
  43.  !       ! 

          !                !         !
  44.  !       ! 

          !                !         !     
  45.  !       ! 

          !                !         !        !! 
  46.  !       ! 

         !         !      !                   !!  !         !  !           !  
  47.  !       ! 

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

         !         !      !                   !!       !                   !! 
  49.  !       ! 

         !         !      !                   !!  Understanding      !                   !! 
  50. mni pl Single Responsibility Testing

  51. describe "Panda" do end

  52. describe "Panda" do let(:bamboo) { double("bamboo").as_null_object } end

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

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

    } ! it "munches bamboo" do end end
  55. describe "Panda" do let(:bamboo) { double("bamboo").as_null_object } subject { Panda.new(bamboo)

    } ! it "munches bamboo" do subject.eat! end end
  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
  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
  58. asdj zoxc mmr qu psoi rnzc vnkl la later, fixing

    a bug ~ ~
  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
  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
  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
  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
  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
  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
  65. asdj zoxc mmr qu psoi rnzc vnkl la one day,

    I find it ~ ~
  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
  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 ? ? ?
  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 ? ? ?
  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?
  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?
  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?
  72. nini lkre We should know these answers before opening the

    test!
  73. drt byby The purpose, rules, and structure of each test

    should be immediately clear
  74. kpo qw A single test can't address all of our

    motivations
  75. zxc eqr Such tests are unclear:

  76. zxc eqr • purpose is hazy Such tests are unclear:

  77. zxc eqr • purpose is hazy • rules are debatable

    Such tests are unclear:
  78. zxc eqr • purpose is hazy • rules are debatable

    • structure is ad hoc Such tests are unclear:
  79. tyu fd Unclear tests cost money

  80. awe voOa Unclear tests must constantly have their:

  81. awe voOa Unclear tests must constantly have their: • purpose

    rediscovered
  82. awe voOa Unclear tests must constantly have their: • purpose

    rediscovered • rules renegotiated
  83. awe voOa Unclear tests must constantly have their: • purpose

    rediscovered • rules renegotiated • structure reorganized
  84. xmcu peo None of those activities have value!

  85. ae r Every suite should promote at most type of

    confidence
  86. ae r Every suite should promote at most type of

    confidence 
  87. c z Every suite should promote at most type of

    understanding
  88. c z Every suite should promote at most type of

    understanding 
  89. suite design zxcm nz

  90. oeiz jdk Omakase Rails

  91. oeiz jdk Omakase Rails MiniTest

  92. oeiz jdk Omakase Rails Views MiniTest

  93. oeiz jdk Omakase Rails Views MiniTest MiniTest

  94. oeiz jdk Omakase Rails Controllers Views MiniTest MiniTest

  95. oeiz jdk Omakase Rails Controllers Views MiniTest MiniTest MiniTest

  96. oeiz jdk Omakase Rails Controllers Views Models MiniTest MiniTest MiniTest

  97. oeiz jdk Omakase Rails Controllers Views Models MiniTest MiniTest MiniTest

  98. ri xc Prime Rails

  99. ri xc Prime Rails Cucumber

  100. ri xc Prime Rails UI Cucumber

  101. ri xc Prime Rails RSpec UI Cucumber

  102. ri xc Prime Rails Views RSpec UI Cucumber

  103. ri xc Prime Rails Views RSpec RSpec UI Cucumber

  104. ri xc Prime Rails Controllers Views RSpec RSpec UI Cucumber

  105. ri xc Prime Rails Controllers Views RSpec RSpec RSpec UI

    Cucumber
  106. ri xc Prime Rails Controllers Views Models RSpec RSpec RSpec

    UI Cucumber
  107. ri xc Prime Rails Controllers Views Models RSpec RSpec RSpec

    UI Cucumber
  108. zpo qw "Fast Specs" Rails Controllers Views Models RSpec RSpec

    RSpec UI Cucumber
  109. zpo qw "Fast Specs" Rails Controllers Views Models RSpec RSpec

    RSpec UI Cucumber RSpec
  110. POROs zpo qw "Fast Specs" Rails Controllers Views Models RSpec

    RSpec RSpec UI Cucumber RSpec
  111. What's the problem? rRth asd

  112. Redundant test coverage rRth asd

  113. ri xc One model change Controllers Views Models RSpec RSpec

    RSpec UI Cucumber
  114. ri xc One model change Controllers Views Models RSpec RSpec

    RSpec UI Cucumber
  115. ri xc One model change Controllers Views Models RSpec RSpec

    RSpec UI Cucumber
  116. ri xc One model change Controllers Views Models RSpec RSpec

    RSpec UI Cucumber
  117. ri xc One model change Controllers Views Models RSpec RSpec

    RSpec UI Cucumber
  118. ri xc One model change Controllers Views Models RSpec RSpec

    RSpec UI Cucumber
  119. ri xc One model change Controllers Views Models RSpec RSpec

    RSpec UI Cucumber
  120. Which leads to: rRth asd

  121. ji cnzm Controllers Views Models UI RSpec (›°□°ʣ›ớ ᵲᴸᵲ Rails

  122. None
  123. architecture jd qr

  124. + -

  125. + - app

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

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

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

    @computes_portion.compute(plan) ) end end provides_meal.rb
  130. suite design slp er

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

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

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

    data panda data cage control service
  135. + - app

  136. + -

  137. The greatest test of all: dk rrt

  138. Does our software serve its purpose? qwe rtb

  139. Wait… what is its purpose? zl dfr

  140. Generating revenue? asd er

  141. Cutting costs? eit dfp

  142. Limiting our liability? xcg ke

  143. Funding non-profits? xd asdasdrg

  144. Can we write a test for those outcomes? zc er

  145. Maybe!* zc er

  146. Maybe!* zc er *But not in this talk.

  147. + -

  148. + - app

  149. Smoke tests oi fg app

  150. Acceptance tests zxc cxoije app

  151. Feature tests rv cm app

  152. End-to-end tests zoc qwe app

  153. Integration tests xu vll app

  154. Integration tests xu vll app

  155. as cjhf app Smoke Acceptance Feature End-to-end

  156. a cv app Smoke Acceptance Feature End-to-end

  157. ed cx app S A F E

  158. zfh ie app SAFE tests

  159. The test's "user"

  160. Confidence sought

  161. Understanding gained

  162. Guidelines

  163. Warning Signs

  164. app ec ze

  165. SAFE

  166. A real-world user SAFE

  167. web apps app SAFE

  168. http services app $ curl http:// SAFE

  169. SAFE

  170. Application works when it's all glued together SAFE

  171. SAFE

  172. "How simple is our product?" SAFE

  173. Can't fit your tests in 30 minutes? SAFE

  174. Can't fit your tests in 30 minutes? SAFE The app

    is complex
  175. SAFE Can't write a test in 30 minutes?

  176. SAFE Can't write a test in 30 minutes? The app

    is complicated
  177. SAFE

  178. SAFE tests shouldn't know internal APIs SAFE

  179. Web tests should bind to user-visible text, not markup SAFE

  180. Enforce a fixed-time budget SAFE

  181. Time-box the suite 5 minutes 5 minutes SAFE

  182. Time-box the suite 5 minutes 5 minutes monthly financials SAFE

  183. Time-box the suite 5 minutes 5 minutes monthly financials search

    SAFE
  184. Time-box the suite 5 minutes 5 minutes monthly financials process

    order search SAFE
  185. Time-box the suite 5 minutes 5 minutes monthly financials process

    order ad words search SAFE
  186. Time-box the suite 5 minutes 5 minutes sign-up monthly financials

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

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

    process order ad words search daily deals ? SAFE
  189. SAFE

  190. SAFE Failures due to refactors are false negatives

  191. SAFE Beware: human intuition overvalues "realistic" tests

  192. SAFE Building multiple releases & branches is expensive

  193. SAFE Superlinear Slowdown

  194. SAFE Superlinear Slowdown More tests Slower build

  195. SAFE Superlinear Slowdown

  196. SAFE Superlinear Slowdown Bigger System Slower build

  197.  !       ! 

          !                !         !        !!  SAFE
  198.  !       ! 

          !                !         !        !!  SAFE
  199.  !       ! 

          !                !         !        !!  SAFE
  200. + - app

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

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

    web back- end web app #1 cage control service
  203. Good SAFE tests are accurate ef zc

  204. But they're also expensive asd tg

  205. And they don't inform our public API's design ef gi

  206. Every library or service you write is consumed by somebody

    tg gz
  207. Verify behavior & demonstrate usage with Consumption tests rRth asd

  208. Consumption

  209. Your 's consumer Consumption

  210. Your 's consumer Consumption service

  211. Your 's consumer Consumption library

  212. Your 's consumer Consumption user interface

  213. Your 's consumer Consumption repository

  214. Consumption

  215. Verifies behavior you're directly responsible for Consumption

  216. Consumption

  217. Answers: "Is it usable?" Consumption

  218. If it's hard to test, then it's hard to use

    Consumption
  219. Consumption

  220. Module boundaries should be meaningful beyond testing Consumption

  221. Consumption Fakes all external dependencies

  222. Consumption Fakes all external dependencies (i.e. can run without access

    to other services)
  223. Consumption Fakes all external dependencies (i.e. can run without access

    to other services) (e.g. in Travis CI)
  224. Exercises public, not private APIs Consumption

  225. Organized by consumers' desired outcomes Consumption

  226. Consumption

  227. Keep consumption tests really fast Consumption

  228. faked services Consumption no good reason to be slow

  229. The only suite that says you just broke something Consumption

  230.  !       ! 

          !                !         !        !!  Consumption
  231.  !       ! 

          !                !         !        !!  Consumption
  232.  !       ! 

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

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

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

    that GET /walruses still returns walruses?" xc r
  236. Why not test across service boundaries? q od

  237. Inter-service tests are easy! cd fe

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

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

    writing them 2. Continue to not write them
  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!
  241. qwe sd Inter-service tests are tempting, but they're .

  242. Inter-service tests are tempting, but they're . hard to set

    up qwe sd
  243. Inter-service tests are tempting, but they're . slow to run

    qwe sd
  244. Inter-service tests are tempting, but they're . redundant coverage qwe

    sd
  245. The root question indicates a lack of trust aie wq

  246. Default to trusting your depended-on services zxc see

  247. ... but sometimes trust isn't appropriate! poae fg

  248. Sometimes our usage is abnormal or unsupported xcg asd

  249. Sometimes other teams demonstrate blind-spots iocv hgt

  250. When trust isn't enough, try writing Contract tests zx rrr

  251. Contract

  252. The "user" is us! Contract

  253. Test is written to represent your interests in somebody else's

    repo Contract
  254. Your needs become part of their Consumption suite Contract

  255. If they break your test, they know to call you!

    Contract
  256. Speedier Feedback Contract fast slow

  257. Speedier Feedback Contract production release fast slow

  258. Speedier Feedback Contract production release git push fast slow

  259. Contract

  260. Dependencies that we own behave how we need them to

    Contract
  261. Contract

  262. We learn: "is this service a good fit for us?"

    Contract
  263. Frequent failures may reveal differing priorities Contract

  264. The maintainer learns: "are people using our service as we

    expect (or desire)?" Contract
  265. Maybe this isn't the best service for them Contract

  266. Maybe this isn't the best service period. Contract ,

  267. Contract

  268. Written just like consumption tests Contract

  269. Committed into the repo of the depended-on service Contract

  270. Maintainers can lower barrier of entry by providing conveniences Contract

  271. Contract

  272. Not a replacement for human interaction Contract

  273.  !       ! 

          !                !         !        !!  Contract
  274.  !       ! 

          !                !         !        !!  Contract
  275.  !       ! 

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

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

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

    @releases_food.release( @computes_portion.compute(plan) ) end end
  280. What about TDD? zxc ei

  281. "What's the point?" eq rf

  282. "We already have lots of tests!" xc fe

  283. So far, no feedback about code's design ei kt

  284. You already have a definition for "unit" test eq xc

  285. I wrote about this a few months ago xi x

  286. I wrote about this a few months ago xi x

    (just Google "tdd failure")
  287. None
  288. It even elicited a response from Uncle Bob! qw rf

  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
  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
  291. There's no "one true TDD" iz rgr

  292. The principal value of TDD in this model is discovery

    vj sdf
  293. Discovery of tiny, boring, consistent units that break big, scary

    problems down into small, manageable ones ri gh
  294. Discovery

  295. The first caller of a new method Discovery

  296. Concerned primarily with inputs and output (or side effect) Discovery

  297. Also concerned with basic code design details Discovery

  298. Inputs & Outcome Discovery Feed Zoo Animals

  299. Inputs & Outcome Discovery Feed Zoo Animals (walrus, cheese)

  300. Inputs & Outcome Discovery Feed Zoo Animals (walrus, cheese) Walrus

    has cheese
  301. Discovery Now what?!

  302. Discovery describe FeedsAnimals do end

  303. Discovery describe FeedsAnimals do describe "#feed" do end end

  304. Discovery describe FeedsAnimals do describe "#feed" do expect(my_face).to look_like(ಠ_ಠ) end

    end
  305. Discovery Feed Zoo Animals Code by wishful thinking!

  306. Discovery Build Feed Plan Provide Meal Feed Zoo Animals Code

    by wishful thinking!
  307. Discovery The test is our sounding board Build Feed Plan

    Provide Meal Feed Zoo Animals
  308. Discovery describe FeedsAnimals do ! ! ! end

  309. Discovery describe FeedsAnimals do Given(:builds_feed_plan) { gimme(BuildsFeedPlan) } ! !

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

    gimme(ProvidesMeal) } ! ! end
  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
  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
  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
  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
  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
  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
  317. Discovery Now I have two problems! Build Feed Plan Provide

    Meal
  318. Discovery Now I have two problems! Build Feed Plan Provide

    Meal  
  319. Discovery

  320. Correct behavior of logical leaf nodes Discovery

  321. (a.k.a. pure, first- order functions) Discovery

  322. Discovery Feed Zoo Animals Build Feed Plan Provide Meal

  323. Discovery Feed Zoo Animals Fetch Schedule Plan Meal Build Feed

    Plan Provide Meal
  324. Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

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

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

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

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

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

    Portions Release Food ✔️ Build Feed Plan Provide Meal
  330. Discovery

  331. Small things Discovery

  332. Small things Discovery (Free SRP!)

  333. Separation of Roles Discovery

  334. Discovery Feed Zoo Animals Fetch Schedule Plan Meal Compute Portions

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

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

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

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

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

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

    Release Food Build Feed Plan Provide Meal Command Query Query Logic Logic Command
  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
  342. Discovery

  343. Command & Query tests discover dependencies with test doubles Discovery

  344. Discovery Logic tests discover implementation by usage

  345. Discovery (i.e. no test doubles) Logic tests discover implementation by

    usage
  346. Commands and Queries contain very little logic Discovery

  347. Pain is good! Discovery

  348. Discovery

  349. Discovery tests yield small, disposable units Discovery

  350. Discovery tests yield small, disposable units Discovery ...so don't be

    afraid to throw them away!
  351. If requirements change, trash a minimal sub-tree of units and

    drive out a new solution Discovery
  352. Re-use is overrated Discovery

  353. Extract refactors are a smell Discovery

  354. Frameworks will fight you! Discovery

  355. Frameworks & TDD try to solve the same problems Discovery

  356. Frameworks provide an orderly structure Discovery

  357. TDD is an approach for discovering an orderly structure Discovery

  358. Discovery testing is at odds with most app frameworks Discovery

  359.  !       ! 

          !                !         !        !!  Discovery
  360.  !       ! 

          !                !         !        !!  Discovery
  361.  !       ! 

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

    @releases_food.release( @computes_portion.compute(plan) ) end end
  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
  364. "Wow, that's a lot of !" zxc tg mock objects

  365. "Wow, that's a lot of !" fake stuff zxc tg

  366. "Wow, that's a lot of !" test doubles zxc tg

  367. "Aren't those many test doubles a pain?" ad er

  368. They can be! asd xc

  369. Note: only use doubles when testing collaborators g rg

  370. Note: better test double libraries are better gr cz

  371. kdasd fk Discovery tests try to improve dependencies' APIs

  372. kg er But we can't change 3rd party APIs

  373. er zxc Mocking what you don't own leads to useless

    pain
  374. Wrap 3rd party API calls in adapters that you do

    own uc vt
  375. Wrap 3rd party API calls in adapters that you do

    own uc vt (And mock those adapters instead)
  376. Typically, adapters shouldn't need tests zx bt

  377. Most tests exercise features that make use 3rd party APIs

    jd hn
  378. It sometimes make sense to test code we don't own

    separately jd hn
  379. When you want to respond to 3rd party failures differently,

    write Adapter tests jd hn
  380. Adapter

  381. Your application, pondering its relationship with a 3rd party API

    Adapter
  382. Exercises your adapter API under realistic-enough circumstances Adapter

  383. Adapter

  384. Adapter Tests of libraries warn of unsafe upgrades

  385. Adapter Tests of network services warn of outages & breaking

    changes
  386. Adapter

  387. Adapters (& tests) specify how you depend on a thing

    Adapter
  388. Establishes boundaries, prevents 3rd party API references from seeping throughout

    your app Adapter
  389. Drastically reduces the cost of replacing dependencies later Adapter

  390. Adapter

  391. Only test adapters with good cause Adapter

  392. "Don't test the framework." Adapter

  393. Adapter

  394. Adapter test suites of network code can be tricky to

    run in CI Adapter
  395. It's easier to test 3rd party services from your SAFE

    suite Adapter
  396. All adapter tests are likely to be slow in ways

    outside your control Adapter
  397.  !       ! 

          !                !         !        !!  Adapter
  398.  !       ! 

          !                !         !        !!  Adapter
  399.  !       ! 

          !                !         !        !!  Adapter
  400. And that's just way to break up your test suite

    asd
  401. And that's just way to break up your test suite

    asd 
  402. My name is Justin Searls Please tweet me @searls &

    Say hello@testdouble.com
  403. Like everyone, we're hiring! Just join@testdouble.com

  404. Please say hello if your team could use our team's

    help #
  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