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

TDD using Minitest

Cd338fedd59e7d02e9479229679354f3?s=47 diogenes
August 08, 2015
180

TDD using Minitest

Talk gave in the 1º Tech Day, GURU-PR 2015 @ EBANX Headquarters

Cd338fedd59e7d02e9479229679354f3?s=128

diogenes

August 08, 2015
Tweet

Transcript

  1. TDD using Minitest 1º Tech Day, GURU-PR 2015

  2. Agenda • Test-Driven Development ◦ Overview ◦ Why to use

    • Minitest ◦ Overview ◦ How to use
  3. Test-Driven Development

  4. "... a software development process that relies on the repetition

    of a very short development cycle: first the developer writes an (initially failing) automated test case that defines a desired improvement, then produces the minimum amount of code to pass that test, and finally refactors the new code to acceptable standards." Wikipedia
  5. Process vs. Quality

  6. Smart developers can make Progress without Process ...but it's not

    good!
  7. Process is the difference between... Surgery and Cutting people open

  8. Process is the difference between... Software Engineering and Programming

  9. Professionals: Design, Plan and Prepare first

  10. Process - The TDD Cycle

  11. None
  12. Benefits of the Test First approach

  13. Requirements. Think about it first...

  14. Better Code Design

  15. Better Code Design • Focus on How to use, its

    Interface/API "the expected behavior" rather than "how this is implemented"
  16. Better Code Design It's all about feedback!

  17. Better Code Design

  18. Simple vs Complex

  19. Better Code Design • Feedback from Test Smells ◦ Over-mocking

    ◦ Hard to write tests ◦ Too much responsibility ◦ Too many assertions
  20. Code Design Feedback - Example describe User do subject {

    User.new } describe "its registration process" do let(:address) { AnObject.new } let(:phone) { Another.new } let(:children) { OtherOne.new } let(:mailer) { AnyObject.new } # etc... it "saves the related address" do # Test saving of the address end it "saves the related children" do # Test saving of children end it "saves the related phones" ... it "saves the user" ... it "sends and email to the user" ... end end
  21. Live Documentation

  22. Any broken code?

  23. Minitest - Overview

  24. What's Minitest? • Replacement for Ruby 1.8's test/unit ◦ Originally

    90 lines of code • Available built-in with Ruby 1.9 • Available as a gem • Meant to be small, clean, and very fast
  25. What's Minitest? 6 parts • runner: The heart of the

    machine • minitest/unit: TDD API • minitest/spec: BDD API • minitest/mock: Simple mocking API • minitest/pride: IO pipelining example • minitest/bench: Abstract benchmark API
  26. Minitest Philosophy • Less is more ◦ Very small in

    comparison with RSpec ◦ Very Fast • Isolated Tests ◦ Test Randomization: Prevents order dependencies • Indirection is the Enemy ◦ Failures pointing to the failure
  27. Minitest vs. RSpec Lines of Code (2015) • Minitest: 1,589

    • RSpec: 15,095
  28. Minitest vs. RSpec

  29. It's just Ruby! Magic free!

  30. Test Cases are Classes

  31. Tests are Methods

  32. minitest/unit require 'minitest/autorun' class CatTest < Minitest::Unit::TestCase def test_meow assert_equal

    "Meoooow!", Cat.say_meow end end
  33. minitest positive assertions assert assert_block * assert_empty assert_equal assert_in_delta assert_in_epsilon

    assert_includes assert_instance_of assert_kind_of assert_match assert_nil assert_operator assert_output * assert_predicate assert_raises * assert_respond_to assert_same assert_send * assert_silent * assert_throws *
  34. minitest negative assertions refute refute_empty refute_equal refute_in_delta refute_in_epsilon refute_includes refute_instance_of

    refute_kind_of refute_match refute_nil refute_operator refute_predicate refute_respond_to refute_same
  35. minitest/spec require 'minitest/autorun' describe Cat do it "says meow" do

    Cat.say_meow.must_equal "Meoooow!" end end
  36. minitest expectations must_be must_be_close_to must_be_empty must_be_instance_of must_be_kind_of must_be_nil must_be_same_as must_be_silent

    * must_be_within_delta must_be_within_epsilon must_equal must_include must_match must_output * must_raise * must_respond_to must_send * must_throw *
  37. minitest negative expectations wont_be wont_be_close_to wont_be_empty wont_be_instance_of wont_be_kind_of wont_be_nil wont_be_same_as

    wont_be_within_delta wont_be_within_epsilon wont_equal wont_include wont_match wont_respond_to
  38. Minitest Ecosystem minitest-chef-handler minitest-reporters minitest-rails guard-minitest minitest-spec-rails minitest-capybara spork-minitest minitest-metadata

    minitest-rails-capybara minitest-matchers capybara_minitest_spec minitest-colorize minitest-rg minitest-ci (many more…)
  39. TDD + Minitest

  40. Red - Write the test require 'minitest/autorun' describe Article do

    subject { Article.new } it "can be posted on Twitter" do subject.post_on_twitter subject.twitted?.must_equal true end end
  41. Red - See it failing $ruby -Ilib spec/article_spec.rb spec/article_spec.rb:3:in `<main>':

    uninitialized constant Article (NameError)
  42. Green - Implements the code class Article end

  43. Red - See it failing $ ruby -Ilib spec/article_spec.rb Run

    options: --seed 34214 1) Error: Article#test_0001_can be posted on Twitter: NoMethodError: undefined method `post_on_twitter' for #<Article:0x000000012c75d0> spec/article_spec.rb:8:in `block (2 levels) in <main>' 1 runs, 0 assertions, 0 failures, 1 errors, 0 skips
  44. Green - Implements the code class Article def post_on_twitter end

    end
  45. Red - See it failing $ ruby -Ilib spec/article_spec.rb Run

    options: --seed 47611 1) Error: Article#test_0001_can be posted on Twitter: NoMethodError: undefined method `twitted?' for #<Article: 0x00000002347130> spec/article_spec.rb:9:in `block (2 levels) in <main>' 1 runs, 0 assertions, 0 failures, 1 errors, 0 skips
  46. Green - Implements the code class Article # ... def

    twitted? end end
  47. Red - See it failing $ ruby -Ilib spec/article_spec.rb Run

    options: --seed 19132 # Running: F... 1) Failure: Article#test_0001_can be posted on Twitter [spec/article_spec. rb:9]: Expected: true Actual: nil
  48. Green - Implements the code class Article def post_on_twitter #

    Logic to post the article (...) @twitted = true end end
  49. Green - Implements the code class Article # ... def

    twitted? @twitted end end
  50. Green - See it passing % ruby -Ilib spec/article_spec.rb Run

    options: --seed 37685 # Running: ......................................................... ............. (etc) Finished in 0.107130s, 1446.8403 runs/s, 2959.0217 assertions/s. 155 runs, 317 assertions, 0 failures, 0 errors, 0 skips
  51. Green - See it passing % ruby -Ilib spec/article_spec.rb Run

    options: --seed 37685 # Running: ......................................................... ............. (etc) Finished in 0.107130s, 1446.8403 runs/s, 2959.0217 assertions/s. 155 runs, 317 assertions, 0 failures, 0 errors, 0 skips
  52. Refactor - Improving the code

  53. Q&A?

  54. Thanks! github.com/diogenes