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

About TDD at Cookpad Summer Intern 2016 day1

About TDD at Cookpad Summer Intern 2016 day1

MOROHASHI Kyosuke

August 12, 2016
Tweet

More Decks by MOROHASHI Kyosuke

Other Decks in Programming

Transcript

  1. $ cd # お好きなところ $ mkdir clock # 好きな名前 $

    cd clock $ git init Bootstrap ‣ ৽͘͠ͳʹ͔Λ͢Δͱ͖͸ɺσΟϨΫτϦΛͭͬͯ͘
 ͙͢(JUͰ؅ཧ࢝͠ΊΔश׳Λ͚ͭ·͠ΐ͏ɻ 
  2. $ gem install bundler $ bundle init $ vim Gemfile

    ``` # frozen_string_literal: true # A sample Gemfile source "https://rubygems.org" gem "rspec" ``` $ bundle install $ git add . $ git commit -m 'bundle init' Bootstrap 
  3. $ bundle exec rspec --init $ git add . $

    git commit -m 'rspec --init' Bootstrap 
  4. $ vim spec/clock_spec.rb ``` describe 'Clock' do specify { expect(true).to

    be true } end ``` ``` $ bundle exec rspec spec/clock_spec.rb . Finished in 0.00097 seconds (files took 0.09778 seconds to load) 1 example, 0 failures ``` ࠷ॳͷҰา 
  5. ``` describe Clock do specify { expect(Clock).to be_an_instance_of(Class) } end

    ``` $ bundle exec rspec spec bundler: failed to load command: rspec 
 (/opt/brew/opt/rbenv/versions/2.3.0/bin/rspec) NameError: uninitialized constant Clock ClockΫϥεΛ࡞Γ͍ͨ → ·ͩͳ͍͔ΒΤϥʔʹͳΔ͸ͣ 
  6. $ mkdir lib $ vim lib/clock.rb ``` class Clock end

    ``` $ bundle exec rspec spec bundler: failed to load command: rspec 
 (/opt/brew/opt/rbenv/versions/2.3.0/bin/rspec) NameError: uninitialized constant Clock ClockΫϥεΛ࡞Δ → ಡΈࠐ·ͳ͍ͱࢀরͰ͖ͳ͍ͷ͸มΘΒͳ͍͸ͣ 
  7. ``` require 'clock' describe Clock do specify { expect(Clock).to be_an_instance_of(Class)

    } end ``` $ bundle exec rspec spec . Finished in 0.00462 seconds (files took 0.09435 seconds to load) 1 example, 0 failures require΋ͨ͠ˠ͜ΜͲͦ͜௨Δ͸ͣ 
  8. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -2,4 +2,10 @@ require 'clock'

    describe Clock do specify { expect(Clock).to be } + + context 'new(10, 20, 00)' do + let(:clock) { Clock.new(10, 20, 0) } + + specify { expect(clock.hour).to eq(10) } + end end ࣮श1: 5෼ ΠϯελϯεΛੜ੒͢Δςετ ‣ ࣮ߦલʹ ͜ͷςετΛ࣮ߦ͢ΔͱͲ͏ͳΓͦ͏͔ɺ༧૝͠ͳ͍͞ɻ ‣ ࣮ߦ͠ɺ݁ՌΛ֬ೝ͠ͳ͍͞ 
  9. $ bundle exec rspec .F Failures: 1) Clock new(10, 20,

    00) Failure/Error: let(:clock) { Clock.new(10, 20, 0) } ArgumentError: wrong number of arguments (given 3, expected 0) # ./spec/clock_spec.rb:7:in `initialize' # ./spec/clock_spec.rb:7:in `new' # ./spec/clock_spec.rb:7:in `block (3 levels) in <top (required)>' # ./spec/clock_spec.rb:9:in `block (3 levels) in <top (required)>' Finished in 0.00186 seconds (files took 0.08364 seconds to load) 2 examples, 1 failure Failed examples: rspec ./spec/clock_spec.rb:9 # Clock new(10, 20, 00) ੜ੒͢ΔςετˠίϯετϥΫλҾ਺͕ҧࣦͬͯഊ͢Δ͸ͣ 
  10. ``` --- a/lib/clock.rb +++ b/lib/clock.rb @@ -1,2 +1,8 @@ class

    Clock + def initialize(*args) + end + + def hour + 10 + end end ``` Fake it (Ծ࣮૷) 
  11. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -8,4 +8,10 @@ describe Clock

    do specify { expect(clock.hour).to eq(10) } end + + context 'new(12, 30, 00)' do + let(:clock) { Clock.new(12, 30, 0) } + + specify { expect(clock.hour).to eq(12) } + end end ࡾ֯ଌྔ (Triangulate) ‣ ࣦഊ͢ΔςετΛ௥Ճ͢Δ ‣ ͷςετ͕௨Δ··ɺͷςετΛ௨͢Α͏ͳɺ࠷௿ݶͷ࣮૷Λ ࡞Δ 
  12. --- a/lib/clock.rb +++ b/lib/clock.rb @@ -1,8 +1,9 @@ class Clock

    - def initialize(*args) + def initialize(hour, *) + @hour = hour end def hour - 10 + @hour end end 12:30ͷςετΛ௨͢Α͏ͳɺ࠷௿ݶͷ࣮૷ 
  13. --- a/lib/clock.rb +++ b/lib/clock.rb @@ -1,9 +1,8 @@ class Clock

    + attr_reader :hour + def initialize(hour, *) @hour = hour end - def hour - @hour - end end {ಈ࡞͢Δ && ͖Ε͍ͳ}ίʔυΛ໨ࢦͯ͠ 
  14. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -1,8 +1,6 @@ require 'clock'

    describe Clock do - specify { expect(Clock).to be_an_instance_of(Class) } - context 'new(10, 20, 00)' do let(:clock) { Clock.new(10, 20, 0) } ςετίʔυ΋ϦϑΝΫλϦϯά͢Δ 
  15. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -5,6 +5,8 @@ describe Clock

    do let(:clock) { Clock.new(10, 20, 0) } specify { expect(clock.hour).to eq(10) } + specify { expect(clock.min).to eq(20) } + specify { expect(clock.sec).to eq(0) } end context 'new(12, 30, 00)' do ෼ͱඵʹର͢Δςετˠ#hour, #minϝιου͕ͳ͍ͷͰࣦഊ͢Δ͸ͣ 
  16. --- a/lib/clock.rb +++ b/lib/clock.rb @@ -1,8 +1,10 @@ class Clock

    - attr_reader :hour + attr_reader :hour, :min, :sec - def initialize(hour, *) + def initialize(hour, min, sec) @hour = hour + @min = min + @sec = sec end end ໌നͳ࣮૷ (Obvious Implementation) 
  17. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -14,4 +14,9 @@ describe Clock

    do specify { expect(clock.hour).to eq(12) } end + + context 'new(12, 30, 60)' do + specify { expect { Clock.new(12, 30, 60) }.to raise_error(ArgumentError) } + end + end ࣮श2: 15෼ ҎԼͷςετΛ࡞੒͠ɺࣦഊΛ֬ೝͨ͠͏͑Ͱ࣮૷͠ͳ͍͞ 
  18. --- a/lib/clock.rb +++ b/lib/clock.rb @@ -2,6 +2,10 @@ class Clock

    attr_reader :hour, :min, :sec def initialize(hour, min, sec) + if (hour >= 24) || (min >= 60) || (sec >= 60) + raise ArgumentError + end + @hour = hour @min = min @sec = sec ਖ਼ͷ਺ͷൣғ֎͚ͩͰΤϥʔʹͳΔ 
  19. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -19,4 +19,7 @@ describe Clock

    do specify { expect { Clock.new(12, 30, 60) }.to raise_error(ArgumentError) } end + context 'new(-12, 30, 59)' do + specify do + expect { Clock.new(-12, 30, 59) }. + to raise_error(ArgumentError) + end + end end ࣮श3ͷςετΛ࢖ͬͯࡾ֯ଌྔ͢Δ 
  20. --- a/lib/clock.rb +++ b/lib/clock.rb @@ -2,7 +2,7 @@ class Clock

    attr_reader :hour, :min, :sec def initialize(hour, min, sec) - if (hour >= 24) || (min >= 60) || (sec >= 60) + if (hour < 0 || hour >= 24) || (min < 0 || min >= 60) 
 || (sec < 0 || sec >= 60) raise ArgumentError end ࣮श2͕άϦʔϯͳ··ɺ࣮श3͕௨Δ࠷௿ݶͷίʔυ 
  21. --- a/lib/clock.rb +++ b/lib/clock.rb @@ -2,13 +2,19 @@ class Clock

    attr_reader :hour, :min, :sec def initialize(hour, min, sec) - if (hour < 0 || hour >= 24) || (min < 0 || min >= 60) || (sec < 0 || sec >= 60) + @hour = verify_valid_clock_input(hour, 24) + @min = verify_valid_clock_input(min, 60) + @sec = verify_valid_clock_input(sec, 60) + end + + private + + def verify_valid_clock_input(val, max) + if (0...max).include?(val) + val + else raise ArgumentError end - - @hour = hour - @min = min - @sec = sec end ϦϑΝΫλϦϯάྫ 
  22. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -22,4 +22,11 @@ describe Clock

    do context 'new(-12, 30, 59)' do specify { expect { Clock.new(-12, 30, 59) }.to raise_error(ArgumentError) } end + + describe '#to_time' do + let(:clock) { Clock.new(10, 20, 0) } + let(:time) { clock.to_time(Date.today) } + + specify { + expect(time.iso8601).to eq ‘2016-08-12T10:20:00+09:00' + } + end end APIΛߟ͑Δ #to_time(<#Date>)͕ૉ௚ͦ͏ˠ#to_timeͷ࣮૷ͳ͍ 
  23. --- a/lib/clock.rb +++ b/lib/clock.rb @@ -7,6 +7,10 @@ class Clock

    @sec = varify_valid_clock_input(sec, 60) end + def to_time(date) + Time.local(2016, 6, 22, 10, 20) + end + private def varify_valid_clock_input(val, max) ճ౴ྫ: Ծ࣮૷ 
  24. ‣ ࣍ͷ೔࣌ɺલͷ೔࣌Λಋग़Ͱ͖Δ ‣ ͖ΐ͏ͷ 10:20 ͸ 2016-08-12T10:20:00 JST ‣ 8/1ͷ

    10:20 ͸ 2016-08-01T10:20:00 JST ࡾ֯ଌྔͷexampleΛ۩ମԽ 
  25. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -25,8 +25,16 @@ describe Clock

    do describe '#to_time' do let(:clock) { Clock.new(10, 20, 0) } - let(:time) { clock.to_time(Date.today) } + context '(Date.today)' do + let(:time) { clock.to_time(Date.today) } - specify { expect(time.iso8601).to eq '2016-06-22T10:20:00+09:00' } + specify { expect(time.iso8601).to eq '2016-06-22T10:20:00+09:00' } + end + + context '(2016-08-01)' do + let(:time) { clock.to_time(Date.new(2016, 8, 1)) } + + specify { expect(time.iso8601).to eq '2016-08-01T10:20:00+09:00' } + end end end ࡾ֯ଌྔ 
  26. --- a/lib/clock.rb +++ b/lib/clock.rb @@ -8,7 +8,7 @@ class Clock

    end def to_time(date) - Time.local(2016, 6, 22, 10, 20) + Time.local(date.year, date.month, date.day, @hour, @min, @sec) end private ࡾ֯ଌྔ 
  27. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -26,7 +26,7 @@ describe Clock

    do describe '#to_time' do let(:clock) { Clock.new(10, 20, 0) } context '(Date.today)' do - let(:time) { clock.to_time(Date.today) } + let(:time) { clock.to_time(Date.new(2016, 6, 22)) } specify { expect(time.iso8601).to eq '2016-06-22T10:20:00+09:0 end ςετίʔυͷվળ: ֎෦ґଘ஋Λແ͘͢ 
  28. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -1,12 +1,12 @@ require 'clock'

    describe Clock do - context 'new(10, 20, 00)' do - let(:clock) { Clock.new(10, 20, 0) } + let(:clock_10_20) { Clock.new(10, 20, 0) } - specify { expect(clock.hour).to eq 10 } - specify { expect(clock.min).to eq 20 } - specify { expect(clock.sec).to eq 0 } + context 'new(10, 20, 00)' do + specify { expect(clock_10_20.hour).to eq 10 } + specify { expect(clock_10_20.min).to eq 20 } + specify { expect(clock_10_20.sec).to eq 0 } end context 'new(12, 30, 00)' do @@ -24,17 +24,20 @@ describe Clock do end describe '#to_time' do - let(:clock) { Clock.new(10, 20, 0) } context '(Date.today)' do - let(:time) { clock.to_time(Date.new(2016, 6, 22)) } + let(:time) { clock_10_20.to_time(Date.new(2016, 6, 22)) } specify { expect(time.iso8601).to eq '2016-06-22T10:20:00+09:00' } end context '(2016-08-01)' do - let(:time) { clock.to_time(Date.new(2016, 8, 1)) } + let(:time) { clock_10_20.to_time(Date.new(2016, 8, 1)) } specify { expect(time.iso8601).to eq '2016-08-01T10:20:00+09:00' } end end ͷɺલʹRefactoring: 
  29. describe Clock do - context 'new(10, 20, 00)' do -

    let(:clock) { Clock.new(10, 20, 0) } + let(:clock_10_20) { Clock.new(10, 20, 0) } - specify { expect(clock.hour).to eq 10 } - specify { expect(clock.min).to eq 20 } - specify { expect(clock.sec).to eq 0 } + context 'new(10, 20, 00)' do + specify { expect(clock_10_20.hour).to eq 10 } + specify { expect(clock_10_20.min).to eq 20 } + specify { expect(clock_10_20.sec).to eq 0 } Refactoring: ‣ `Clock.new(10, 20, 0)`͕සग़͢ΔͷͰɺ໊લΛ͚ͭͯɺ·ͱΊΔ ‣ ςετίʔυ಺ͷ৘ใྔ͕૿͑Δ ‣ νϟϯΫԽ͢Δ͜ͱʹΑΓɺϓϩάϥϚ͕֮͑Δ͜ͱ͕ݮΔ 
  30. --- a/spec/clock_spec.rb +++ b/spec/clock_spec.rb @@ -37,7 +37,9 @@ describe Clock

    do end end + describe '#next_time(time)' do + let(:time) { Time.local(2016, 8, 11, 12, 30) } + specify { + expect(clock_10_20.next_time(time).iso8601).to \ + eq ‘2016-08-12T10:20:00+09:00' + } end end ·ͣ͸RED→ #next_time()͕ͳ͍͔ΒNME