Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

なぜテストを書くの?(または書かないの?) 〜テストコードの7つの役割〜 / #tamarub...

なぜテストを書くの?(または書かないの?) 〜テストコードの7つの役割〜 / #tamarubykaigi01

Tama Ruby会議01のキーノートとして発表したスライドです。
https://tama-rb.github.io/tamarubykaigi01/

参加レポートはこちら。
https://blog.jnito.com/entry/2019/07/07/102734

Junichi Ito

July 06, 2019
Tweet

More Decks by Junichi Ito

Other Decks in Technology

Transcript

  1. !11 ࠓ೔͓࿩͢͠Δ͜ͱͱɺࠓ೔ͷΰʔϧ • ԿͷͨΊʹςετΛॻ͘ͷ͔ɺͦͷ໨తʢ໾ׂʣΛ7ͭ঺հ͠·͢ • Ϛον͢Δ໨త͕ͳ͚Ε͹ɺςετ͸ॻ͔ͳ͍͍ͯ͘͠ɺॻ͚ͳ͍͜ͱΛઆ໌͠·͢ ࠓ೔ͷΰʔϧ • ʮςετΛॻ͘͜ͱ͕໨తʯͱ͍͏ঢ়ଶΛଔۀ͢Δ •

    ͳͥࣗ෼͕͍ͭ·Ͱͨͬͯ΋ςετ͕ॻ͚ͳ͍ͷ͔ɺͦͷཧ༝ΛཧղͰ͖ΔΑ͏ʹͳΔ ࠓ೔࿩͞ͳ͍͜ͱ • ςΫχοΫతͳ࿩ʢRSpecͷ࢖͍ํ౳ʣ͸ࠓ೔ͷςʔϚʹ͸ؚ·Ε·ͤΜ
  2. !12 ʮςετʯͱ͍͏༻ޠʹ͍ͭͯ • ݹయతͳఆٛ ʹ ςετͱ͸ɺΤϥʔΛΈ͚ͭΔͭ΋ΓͰϓϩάϥϜΛ࣮ߦ͢Δաఔ ‣ ઐ೚ͷςελʔ΍QAΤϯδχΞ͕͍ͨΓ͢Δ͜ͱ΋͋Δ ‣ ॻ੶ʮςετۦಈ։ൃʯ෇࿥CΛࢀর

    • ࠓ೔ͷߨԋ ʹ ςετίʔυɺ·ͨ͸ࣗಈςετͷҙຯ ‣ ։ൃऀࣗ਎͕ॻ͘ ‣ ಛʹ஫ऍΛ෇͚ͳ͚Ε͹ɺͬͪ͜ͷҙຯͩͱߟ͍͑ͯͩ͘͞ • Πϝʔδ͢Δ΋ͷ͕ҟͳΔͱٞ࿦͕͔Έ͋Θͳ͍͜ͱ΋͋ΔͷͰཁ஫ҙ
  3. !15 ॳΊͯͷʮखಈʯςετ • 2003೥ SIerʹத్ೖࣾ • ౰࣌ͷ֨ݴʮಈ͍͍ͯΔϓϩάϥϜ͸৮Δͳʯ • ExcelͰ࡞ͬͨςετ߲໨࢓༷ॻΛݟͳ͕Β໨ࢹͰνΣοΫɺεΫγϣΛషΓ෇͚ •

    ϓϩάϥϜΛमਖ਼ͨ͠Βςετ΋΍Γ௚͠ • ϓϩάϥϜͱҰॹʹςετ݁Ռʢࢴʹҹ࡮ͨ͠΋ͷʣ΋ೲ඼ • ʮ͏ͪ͸ѱ͘ͳ͍Ͱ͢Αʂ΄Βɺ࢓༷ॻ௨Γʹ࡞Γ·ͨ͠Αʂʯͱݴ͍ுΔͨΊͷςετ
  4. • ๻͕ࠓಇ͍͍ͯΔιχοΫΨʔσϯͰॻ͍͍ͯΔςετίʔυΛ૝ఆ͍ͯ͠·͢ • ۩ମతʹ͸ҎԼͷΑ͏ͳ؀ڥͰ͢ ‣ ि୯ҐͰސ٬ͱϛʔςΟϯάΛ։͍ͯ։ൃͱϦϦʔεΛ܁Γฦ͢ ‣ 1Ҋ݅͋ͨΓͷ։ൃϝϯόʔ͸গ਺ ‣ ϦϦʔεલͷPull

    Request͸ίʔυϨϏϡʔ͕ඞਢ ‣ ܰඍͳෆ۩߹Ͱ͋Ε͹։ൃऀ͕͙͢ʹमਖ਼ͯ͠ϦϦʔεՄೳ ‣ RailsͱRSpecΛ࢖ͬͨWebΞϓϦ։ൃͱࣗಈςετ͕ϝΠϯ !23 લఏ৚݅
  5. !26 1. ҆શωοτͱͯ͠ͷ໾ׂ • ςετίʔυ͸ΞϓϦέʔγϣϯͷ҆શωοτɺ໋ߝɺ๷஄νϣοΩ • ػೳΛ௥Ճɾมߋͯ͠΋ɺଞͷ෦෼͕յΕ͍ͯͳ͍͜ͱΛอূ͢Δ • Ruby΍RailsɺgemΛΞοϓσʔτͯ͠΋յΕ͍ͯͳ͍͜ͱΛอূ͢Δ ͳͥςετΛॻ͘ͷ͔ʁ

    • େن໛ͳϓϩάϥϜΛຖճख࡞ۀͰ࠶ςετ͢Δͷ͸ඇݱ࣮త͔ͩΒ • ϓϩάϥϜ͕յΕΔͱސ٬΍ར༻ऀʹ໎࿭ֻ͕͔Δ͔Β • ࠓޙ΋௕͘ӡ༻͞ΕΔݟࠐΈ͕ߴ͍͔Β
  6. !27 ͜Ε͚ͩͰಈ࡞֬ೝ͕ऴΘΔͳΜͯ࠷ߴʂ $ bin/rspec Finished in 5.31 seconds (files took

    2.24 seconds to load) 70 examples, 0 failures $ bundle update rails Bundle updated! $ bin/rspec Finished in 3.91 seconds (files took 0.50523 seconds to load) 70 examples, 0 failures
  7. !30 ྫɿ13ܻͷISBNΛ10ܻʹม׵͢ΔϓϩάϥϜΛςετ͢Δ require './lib/isbn_converter' require 'rspec' RSpec.describe 'isbn_converter' do describe

    '#convert_isbn' do example '13ܻͷISBNΛ10ܻʹม׵Ͱ͖Δ' do expect(convert_isbn('9784774193977')).to eq '4774193976' end example 'νΣοΫσΟδοτ͕10ʹͳΔͱ͖͸XͰऴΘΔ' do expect(convert_isbn('9784774183619')).to eq '477418361X' end end end ࠷ޙͷ1ܻ͕νΣοΫσΟδοτ in 13ܻ out 10ܻ
  8. !33 ྫɿRGBม׵ϓϩάϥϜͷϦϑΝΫλϦϯά def to_ints(hex) r = hex[1..2] g = hex[3..4]

    b = hex[5..6] ints = [] [r, g, b].each do |s| ints << s.hex end ints end def to_ints(hex) hex.scan(/\w\w/).map(&:hex) end class RgbTest < Minitest::Test def test_to_ints assert_equal [0, 0, 0], to_ints('#000000') assert_equal [255, 255, 255], to_ints('#ffffff') assert_equal [4, 60, 120], to_ints('#043c78') end end 16ਐ਺ͷ৭ίʔυΛ10ਐ਺ʹม׵Ͱ͖Δ͜ͱΛݕূ ϦϑΝΫλϦϯάલ ϦϑΝΫλϦϯάޙ ✨ in 16ਐ਺ out 10ਐ਺
  9. !36 ྫɿϢʔβʔొ࿥ޙͷ௨஌ϝʔϧૹ৴Λςετ͢Δ RSpec.describe 'Users', type: :system do describe 'Sign up'

    do example 'Ϣʔβʔొ࿥͢ΔͱWelcomeϝʔϧ͕ૹ৴͞ΕΔ' do visit new_user_registration_path fill_in 'Eϝʔϧ', with: '[email protected]' fill_in 'ύεϫʔυ', with: 'password' expect { click_button 'ొ࿥͢Δ' }.to \ change(ActionMailer::Base.deliveries, :count).by(1) end end end ᶃ Ϣʔβʔొ࿥ը໘Λ։͘ ᶄ ϝΞυͱύεϫʔυΛೖྗ ᶅ ొ࿥͕׬ྃͨ͠Β௨஌ϝʔϧ͕ૹ৴͞ΕΔ͜ͱΛ֬ೝ
  10. !39 ྫɿϢʔβʔݕࡧ࣌ͷෆ۩߹ΛςετΛॻ͍͔ͯΒमਖ਼͢Δ RSpec.describe 'Users', type: :system do let!(:user) { create

    :user, email: '[email protected]', name: 'ҏ౻३Ұ' } describe 'Ϣʔβʔͷݕࡧ' do example 'Eϝʔϧͷେจࣈɾখจࣈ͸ແࢹͯ͠ݕࡧ͢Δ' do visit users_path fill_in 'Eϝʔϧ', with: '[email protected]' click_button 'ݕࡧ͢Δ' expect(page).to have_content 'ҏ౻३Ұ' end end end ↑ मਖ਼લ͸User͕ݟ͔ͭΒͣɺ͜͜Ͱςετ͕ࣦഊ͢Δ খจࣈͰొ࿥ େจࣈͰݕࡧ
  11. !40 ྫɿϢʔβʔݕࡧ࣌ͷෆ۩߹ΛςετΛॻ͍͔ͯΒमਖ਼͢Δ RSpec.describe 'Users', type: :system do let!(:user) { create

    :user, email: '[email protected]', name: 'ҏ౻३Ұ' } describe 'Ϣʔβʔͷݕࡧ' do example 'Eϝʔϧͷେจࣈɾখจࣈ͸ແࢹͯ͠ݕࡧ͢Δ' do visit users_path fill_in 'Eϝʔϧ', with: '[email protected]' click_button 'ݕࡧ͢Δ' expect(page).to have_content 'ҏ౻३Ұ' end end end খจࣈͰొ࿥ େจࣈͰݕࡧ ↑ ͪΌΜͱमਖ਼Ͱ͖ͨΒςετ͕ύε͢Δ
  12. !42 6. ઃܭΛࢧԉ͢Δ໾ׂ • ࣮૷͢ΔલʹςετίʔυΛॻ͖࢝ΊΔͱɺϓϩάϥϜͷઃܭʹ໾ཱͭ ‣ ϝιου໊΍Ҿ਺ɺ໭Γ஋ɺςετύλʔϯͳͲΛςετίʔυ্Ͱݕ౼Ͱ͖Δ ‣ ͍ΘΏΔʮςετϑΝʔετʯͷख๏ •

    ͞Βʹ͔ͦ͜Βର࿩తʹ࣮૷ΛਐΊΔ͜ͱ͕Ͱ͖Δ ‣ ઌʹ͍͔ͭ͘ͷςετέʔεΛॻ͍͓͖ͯɺॱʹάϦʔϯʹ͍ͯ͘͠ ͳͥςετΛॻ͘ͷ͔ʁ • ࣮ࡍʹͦͷϓϩάϥϜΛར༻͢ΔίʔυΛॻ͘͜ͱͰɺઃܭͷྑ͠ѱ͠ʹؾ͚ͮΔ͔Β
  13. !43 ྫɿࣗಈൢചػϓϩάϥϜΛςετ͔Βઌʹॻ͍ͯΈΔ RSpec.describe VendingMachine do example '͓ۚͷ౤ೖͱ෷͍໭͠' do end end

    ※ʮTDDBCେࡕ3.0/՝୊ʯΛࢀߟʹ࡞੒ • ϝιου໊͸Θ͔Γ΍͍͔͢ʁ • Ҿ਺΍໭Γ஋͸͜ΕͰ͍͍͔ʁ • ͓ۚΛද͢Ϋϥε΋࡞Δ΂͖͔ʁ etc machine = VendingMachine.new # 10ԁۄɺ100ԁۄΛ̍ͭͣͭ౤ೖͰ͖Δɻ౤ೖ͸ෳ਺ճͰ͖Δɻ machine.insert 10 machine.insert 10 machine.insert 100 # ౤ೖֹۚͷ૯ܭΛऔಘͰ͖Δɻ expect(machine.money_sum).to eq 120 # ෷͍໭͠ૢ࡞Λߦ͏ͱɺ౤ೖֹۚͷ૯ܭΛ௼Γમͱͯ͠ग़ྗ͢Δɻ expect(machine.return_money).to contain_exactly(10, 10, 100) expect(machine.money_sum).to eq 0 ݕ౼Ͱ͖ͨΒ࣮૷։࢝ʂ
  14. !45 7. આ໌ॻͱͯ͠ͷ໾ׂ • ςετίʔυΛಡΊ͹ɺϓϩάϥϜͷ࢓༷΍σʔλߏ଄͕೺ѲͰ͖Δ • ౷߹ςετʢfeature spec / system

    specʣΛݟΕ͹ɺը໘ͷૢ࡞ํ๏͕Θ͔Δ • gemͷ࢖͍ํ΍Rubyͷ৽ػೳ΋ɺςετΛಡΜͩํ͕෼͔Γ΍͍͢͜ͱ͕͋Δ ͳͥςετΛॻ͘ͷ͔ʁ • ଞͷϝϯόʔ΍কདྷͷࣗ෼͕ɺϓϩάϥϜΛཧղ͠΍͘͢ͳΔ͔Β • ಡΉ͚ͩͰͳ͘ɺಈ͔ͯ֬͠ೝ͢Δ͜ͱ΋Ͱ͖Δ͔Β
  15. !46 ྫɿliberal_parsingΦϓγϣϯͬͯԿʁ def test_liberal_parsing input = '"Johnson, Dwayne",Dwayne "The Rock"

    Johnson' assert_raise(CSV::MalformedCSVError) do CSV.parse_line(input) end assert_equal(["Johnson, Dwayne", 'Dwayne "The Rock" Johnson'], CSV.parse_line(input, liberal_parsing: true)) Ͳ͏΍ΒɺมͳCSVςΩετ΋ ͍͍ײ͡ʹύʔεͯ͘͠ΕΔͬΆ͍ʂ NEWS for Ruby 2.4.0 CSV • Add a liberal_parsing option. [Feature #11839] ← มͳCSVςΩετ ⚠ ;ͭ͏ʹύʔε͢ΔͱΤϥʔ https://github.com/ruby/ruby/blob/trunk/test/csv/test_features.rb ΑΓൈਮ
  16. !51 ࣗ෼ͷࠓͷঢ়گΛ֬ೝͯ͠ΈΑ͏ • େن໛ʢखಈςετ͕ඇݱ࣮తͳϨϕϧʣ • ण໋͕௕͍ • ސ٬΍ར༻ऀʹରͯ͠੹೚Λෛ͍ͬͯΔ • ଞͷ։ൃऀ͕͍Δ

    • ༩͑ΒΕͨ޻਺͕ݶΒΕ͍ͯΔ • ͘͝খن໛ • ण໋͕୹͍ • ੹೚Λෛ͏΂͖ސ٬΍ར༻ऀ͕͍ͳ͍ • ̍ਓͰ։ൃ͍ͯ͠Δ • ޻਺͸ແݶʹ࢖͑Δ ࣗಈςετ͕ෆՄܽ ࣗಈςετͷඞཁੑ͕ݶఆత ࢓ࣄͱͯ͠ίʔυΛॻ͘ਓ͸ͬͪ͜ʁ ಠֶͰษڧͯ͠Δਓ͸ͬͪ͜ʁ
  17. !58 ςετίʔυͷ7ͭͷ໾ׂ 1. ҆શωοτͱͯ͠ͷ໾ׂ 2. ࣮૷ͷਖ਼͠͞Λূ໌͢Δ໾ׂ 3. ίʔυͷ඼࣭Λ޲্ͤ͞Δ໾ׂ 4. লྗԽπʔϧͱͯ͠ͷ໾ׂ

    5. όάΛୟ͖௵͢໾ׂ 6. ઃܭΛࢧԉ͢Δ໾ׂ 7. આ໌ॻͱͯ͠ͷ໾ׂ Ͳͷ໾ׂʢͲͷ໨తʣͰࣗ෼͸ ςετΛॻ͜͏ͱ͍ͯ͠Δͷ͔ɺ ࣗ໰ࣗ౴ͯ͠ΈΑ͏
  18. !59 ࣗ෼ͷࠓͷঢ়گΛ֬ೝͯ͠ΈΑ͏ • େن໛ʢखಈςετ͕ඇݱ࣮తͳϨϕϧʣ • ण໋͕௕͍ • ސ٬΍ར༻ऀʹରͯ͠੹೚Λෛ͍ͬͯΔ • ଞͷ։ൃऀ͕͍Δ

    • ༩͑ΒΕͨ޻਺͕ݶΒΕ͍ͯΔ • ͘͝খن໛ • ण໋͕୹͍ • ੹೚Λෛ͏΂͖ސ٬΍ར༻ऀ͕͍ͳ͍ • ̍ਓͰ։ൃ͍ͯ͠Δ • ޻਺͸ແݶʹ࢖͑Δ ࣗಈςετ͕ෆՄܽ ࣗಈςετͷඞཁੑ͕ݶఆత ςετແ͠͡Όɺ΍͍ͬͯΒΕͳ͍ঢ়گ ςετΛॻ͘ಈػ͕ੜ·Εʹ͍͘ঢ়گ