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

Testing Magic

Testing Magic

An overview of the concepts behind TDD, complete with a run through the much more practical Sandi Metz rules of testing.

It aims at giving you the building blocks to do TDD and actually enjoy it.

Luís Ferreira

May 30, 2013
Tweet

More Decks by Luís Ferreira

Other Decks in Programming

Transcript

  1. Test Driven Development A guy called Kent Beck came up

    with a different way of writing code, and called it
  2. Fixing bugs over and over again Large classes and methods

    Code is a mess Fear of change Hard to refactor
  3. Fixing bugs over and over again Large classes and methods

    Code is a mess Fear of change Hard to refactor these are symptoms of bad practices
  4. RED GREEN REFACTOR stay here as little as possible do

    the smallest step you can go drink a beer
  5. - More focused classes - Looser coupling - Cleaner interfaces

    - More confidence in your code you get: you don’t get: - Bug free code - The best code in the world
  6. Not allowed to write: - code unless it is to

    make a test pass - more of a test than is sufficient to fail - more code than is sufficient to pass the test BOB MARTIN picture source: http://agile2012.agilealliance.org
  7. There is more to testing than TDD, go check it

    out so you can chose your way...
  8. magic tricks of testing Testing is hard, and when you

    make a change that breaks half your tests you feel you’ve been wasting your time. Well, fear not young chap, and come learn some
  9. class Player < Struct.new :height, :weight def body_mass_index (weight /

    height**2).round 1 end end describe Player do context "#body_mass_index" do it "calculates the bmi" do lebron = Player.new 2.03, 113 lebron.body_mass_index.should eq 27.4 end end end object test
  10. class Player < Struct.new :height, :weight attr_reader :skill def skill=(skill_level)

    @skill = skill_level end end describe Player do context "#skill=" do it "updates the skill level" do player.skill = 10 player.skill.should eq 10 end end end object test
  11. Query Command Incoming Sent to self Outgoing Message type Message

    origin Assert result Assert direct public side effects
  12. object class Player < Struct.new :height, :weight def body_mass_index actual_bmi.round

    1 end private def actual_bmi (weight / height**2) end end
  13. object class Player < Struct.new :height, :weight def body_mass_index actual_bmi.round

    1 end private def actual_bmi (weight / height**2) end end
  14. object class Player < Struct.new :height, :weight def body_mass_index actual_bmi.round

    1 end private def actual_bmi (weight / height**2) end end
  15. object class Player < Struct.new :height, :weight def body_mass_index actual_bmi.round

    1 end private def actual_bmi (weight / height**2) end end testing state is redundant
  16. describe Player do context "#body_mass_index" do it "calculates the bmi"

    do lebron = Player.new 2.03, 113 lebron.should_receive(:actual_bmi).and_call_original lebron.body_mass_index.should eq 27.4 end end end test
  17. describe Player do context "#body_mass_index" do it "calculates the bmi"

    do lebron = Player.new 2.03, 113 lebron.should_receive(:actual_bmi).and_call_original lebron.body_mass_index.should eq 27.4 end end end test Over specification: no safety and breaks on every change
  18. Do not test private methods RULE Break at your own

    risk if it saves $$ in development
  19. Query Command Incoming Sent to self Outgoing Message type Message

    origin Assert result Assert direct public side effects
  20. Query Command Incoming Sent to self Outgoing Message type Message

    origin Assert result Assert direct public side effects Ignore
  21. object class Player < Struct.new :height, :weight def on_the_team?(team) team.has_player?

    self end end Player on_the_team? has_player? outgoing incoming Team
  22. test describe Player do context "#on_the_team?" do it "finds if

    player is on the team" do team = Team.new team.add_player player player.should be_on_the_team team team.players.should include player end end end
  23. test Redundant: duplicates team’s tests describe Player do context "#on_the_team?"

    do it "finds if player is on the team" do team = Team.new team.add_player player player.should be_on_the_team team team.players.should include player end end end
  24. test describe Player do context "#on_the_team?" do it "finds if

    player is on the team" do team = Team.new team.add_player player team.should_receive (:has_player?).and_call_original player.should be_on_the_team team end end end
  25. test Over specification: adds costs and no benefits describe Player

    do context "#on_the_team?" do it "finds if player is on the team" do team = Team.new team.add_player player team.should_receive (:has_player?).and_call_original player.should be_on_the_team team end end end
  26. Do not test outgoing query messages RULE If the message

    has no visible side effects the sender should not test it
  27. Query Command Incoming Sent to self Outgoing Message type Message

    origin Assert result Assert direct public side effects Ignore
  28. Query Command Incoming Sent to self Outgoing Message type Message

    origin Assert result Assert direct public side effects Ignore
  29. object class Player < Struct.new :height, :weight def infiltrate_team(team) team.add_player

    self end end describe Player do context "#infiltrate_team" do it "adds player to team" do team = Team.new player.infiltrate_team team team.players.should include player end end end test
  30. object class Player < Struct.new :height, :weight def infiltrate_team(team) team.add_player

    self end end describe Player do context "#infiltrate_team" do it "adds player to team" do team = Team.new player.infiltrate_team team team.players.should include player end end end test depends on distant side effect
  31. object class Player < Struct.new :height, :weight def infiltrate_team(team) team.add_player

    self end end describe Player do context "#infiltrate_team" do it "adds player to team" do team = Team.new player.infiltrate_team team team.players.should include player end end end test not the player’s responsibility
  32. object class Player < Struct.new :height, :weight def infiltrate_team(team) team.add_player

    self end end describe Player do context "#infiltrate_team" do it "adds player to team" do team = Team.new team.should_receive(:add_player) player.infiltrate_team team end end end test this message must be sent
  33. object class Player < Struct.new :height, :weight def infiltrate_team(team) team.add_player

    self end end describe Player do context "#infiltrate_team" do it "adds player to team" do team = Team.new team.should_receive(:add_player) player.infiltrate_team team end end end test this message must be sent depends on the interface
  34. it’s the player responsibility to send add_player to the team

    object class Player < Struct.new :height, :weight def infiltrate_team(team) team.add_player self end end describe Player do context "#infiltrate_team" do it "adds player to team" do team = Team.new team.should_receive(:add_player) player.infiltrate_team team end end end test this message must be sent
  35. EXPECT outgoing command messages to send if side effects are

    stable and cheap, rule might be broken
  36. Query Command Incoming Sent to self Outgoing Message type Message

    origin Assert result Assert direct public side effects Ignore
  37. Query Command Incoming Sent to self Outgoing Message type Message

    origin Assert result Assert direct public side effects Ignore Expect to send
  38. - Test everything, but only once - Test the interfaces

    - Trust collaborators - In doubt, go for simple SUMMARY
  39. - https://speakerdeck.com/skmetz/magic-tricks-of-testing- railsconf?slide=0 - http://butunclebob.com/ ArticleS.UncleBob.TheThreeRulesOfTdd - http://blog.zamith.pt/blog/2013/04/10/understanding-the- heart-to-become-a-better-doctor/ -

    http://www.amazon.com/Clean-Code-Handbook-Software- Craftsmanship/dp/0132350882?tag=viglink127254-20 - http://www.amazon.com/dp/0321721330 - http://www.cleancoders.com - https://learn.thoughtbot.com/purchases/ d27fb3e007037d4ef543caf84d87ecc7 - http://www.amazon.com/RSpec-Book-Behaviour- Development-Cucumber/dp/1934356379 We stand on the shoulders of giants - http://www.amazon.com/Test-Driven- Development-By-Example/dp/0321146530? tag=giantrobotssm-20 - https://peepcode.com/products/rspec-i - https://peepcode.com/products/rspec-ii - http://robots.thoughtbot.com/post/23112388518/ types-of-coupling