$30 off During Our Annual Pro Sale. View Details »

リーダブルテストコード / #vstat

リーダブルテストコード / #vstat

「リーダブルなテストコードについて考えよう ~VeriServe Test Automation Talk No.3~」で使用したスライドです。
https://veriserve-event.connpass.com/event/243280/

登壇動画はこちらで公開されています。
https://vimeo.com/742517199/e001ac43ac

<参考リンク>

Twitter https://twitter.com/jnchito

Blog https://blog.jnito.com/

Qiita https://qiita.com/jnchito

プロを目指す人のためのRuby入門[改訂2版]
https://gihyo.jp/book/2021/978-4-297-12437-3

Everyday Rails - RSpecによるRailsテスト入門
https://leanpub.com/everydayrailsrspec-jp/

https://twitter.com/jnchito/status/1552196880524013569

https://twitter.com/jnchito/status/1539100857991852032

https://twitter.com/jnchito/status/1539100861947064320

Clean Test Code Revised (by Shinichi Maeshima)
https://speakerdeck.com/willnet/clean-test-code-revised

【初心者向け】テストコードの方針を考える(何をテストすべきか?どんなテストを書くべきか?)
https://qiita.com/jnchito/items/2a5d3e15761fd413657a

なぜテストを書くの?(または書かないの?) 〜テストコードの7つの役割〜
https://speakerdeck.com/jnchito/number-tamarubykaigi01

テストコードの期待値はDRYを捨ててベタ書きする ~テストコードの重要な役割とは?~
https://qiita.com/jnchito/items/eb3cfa9f7db752dcb796

僕がRSpecでsubjectを使わない理由
https://blog.jnito.com/entry/2021/10/09/105651

Junichi Ito

July 27, 2022
Tweet

More Decks by Junichi Ito

Other Decks in Programming

Transcript

  1. 5 Hello, world! " • ҏ౻ ३Ұ • גࣜձࣾιχοΫΨʔσϯͷRailsϓϩάϥϚ •

    ϑΟϤϧυϒʔτΩϟϯϓͷϝϯλʔ • ฌݿݝ੢࿬ࢢࡏॅʢϦϞʔτϫʔΫྺ10೥ʣ • ςετίʔυྺ 15೥Ҏ্ʢJUnit → NUnit → RSpecʣ !KODIJUP CMPHKOJUPDPN
  2. 7 ஶॻ ʮϓϩΛ໨ࢦ͢ਓͷͨΊͷRubyೖ໳ʯ ‣ ௨শɾνΣϦʔຊ$ ‣ ग़൛ࣾɿٕज़ධ࿦ࣾ ‣ 2017೥11݄ ୈ̍൛ൃച

    ‣ 2021೥12݄ վగ̎൛ൃചʢRuby 3.0ʹରԠʣ 3VCZͱ5%%͕ಉ࣌ʹֶ΂·͢ʂ ͦͯ͠ʜʜ ㊗ॏ൛ग़དྷʂʢࠓ೔࿈བྷ͕དྷ·ͨ͠&ʣ ͡Ύ͏͸Μ͠Ύ͍ͬͨ
  3. 8 ༁ॻ ʮEveryday Rails - RSpecʹΑΔRailsςετೖ໳ʯ ‣ Aaron Sumner ஶ

    ‣ ग़൛ࣾɿLeanpub ‣ ిࢠॻ੶ͱͯ͠ൃചத ‣ 2014೥2݄ 1stϦϦʔε ‣ 2022೥1݄ Rails 7.0ʹରԠ 34QFDͰ3BJMTΞϓϦΛςετ ͍ͨ͠ਓ͸ͪ͜ΒΛͲ͏ͧʂ
  4. 19 Ϧʔμϒϧͳςετίʔυͷ৚݅ ✅ υΩϡϝϯτͷΑ͏ʹ্͔ΒԼʹૉ௚ʹಡΈԼͤΔ ✅ ม਺Λ࢖Θͣʹจࣈྻ΍਺஋Λϕλॻ͖͢Δ ✅ ڽͬͨςΫχοΫΛཚ༻͠ͳ͍ ❌ ϧʔϓॲཧ΍৚݅෼ذ͕සൃ͢Δʢࢹઢ্͕Լͨ͠Γδϟϯϓͨ͠Γ͢Δʣ

    ❌ ਺஋΍จࣈྻͷΑ͏ͳ୯७ͳσʔλ·Ͱશ෦ม਺ʹ֨ೲ͞Ε͍ͯΔ ❌ shared examples΍subjectͳͲɺςεςΟϯάFWݻ༗ͷػೳΛཚ༻͍ͯ͠Δ ൓ରʹ͢ΔͱʮಡΈʹ͍͘ςετίʔυʯͷͰ͖͕͋Γʂʂ ϑϨʔϜϫʔΫ
  5. 22 ࠓճςετ͢Δϝιου = UserΫϥεͷageϝιου def age today = Date.today this_years_birthday

    = Date.new( today.year, birth_date.month, birth_date.day) ret = today.year - birth_date.year if today < this_years_birthday ret -= 1 end ret end • ࢓༷΍ϩδοΫ͸͋͑ͯઆ໌͠·ͤΜ ※ աڈʹ࣮ࡍʹίʔυϨϏϡʔͨ͠ϓϩάϥϜͱͦͷςετίʔυΛҰ෦վม͍ͯ͠·͢
  6. 23 ๻͕ϨϏϡʔͨ͠ςετίʔυ͸͜Ε let(:user) { create(:user, birth_date: Faker::Date.birthday) } let(:this_year) {

    Date.today.year } let(:this_years_birthday) { Date.new(this_year, user.birth_date.month, user.birth_date.day) } let(:age) { this_year - user.birth_date.year } context "஀ੜ೔Ҏ߱ͷ৔߹" do it "஀ੜ೔Λա͗ͨ೥ྸ͕ฦΔ" do travel_to(this_years_birthday) expect(user.age).to eq(age) end end context "஀ੜ೔Ҏલͷ৔߹" do it "஀ੜ೔લͷ೥ྸ͕ฦΔ" do travel_to(this_years_birthday.yesterday) expect(user.age).to eq(age - 1) end end ໰୊ɿageϝιου͸ͲΜͳ࢓༷ʁ
  7. let(:user) { create(:user, birth_date: Faker::Date.birthday) } let(:this_year) { Date.today.year }

    let(:this_years_birthday) { Date.new(this_year, user.birth_date.month, user.birth_date.day) } let(:age) { this_year - user.birth_date.year } context "஀ੜ೔Ҏ߱ͷ৔߹" do it "஀ੜ೔Λա͗ͨ೥ྸ͕ฦΔ" do travel_to(this_years_birthday) expect(user.age).to eq(age) end end context "஀ੜ೔Ҏલͷ৔߹" do it "஀ੜ೔લͷ೥ྸ͕ฦΔ" do travel_to(this_years_birthday.yesterday) expect(user.age).to eq(age - 1) end end ςετ͢Δϝιου ςετ͢Δϝιου let(:x) { 1 } ɹ x = 1 ͸ Έ͍ͨͳΠϝʔδ travel_to ͸Ҿ਺Ͱࢦఆͨ͠೔෇ʹγεςϜ೔෇Λมߋ͢Δϝιου ←
  8. let(:user) { create(:user, birth_date: Faker::Date.birthday) } let(:this_year) { Date.today.year }

    let(:this_years_birthday) { Date.new(this_year, user.birth_date.month, user.birth_date.day) } let(:age) { this_year - user.birth_date.year } context "஀ੜ೔Ҏ߱ͷ৔߹" do it "஀ੜ೔Λա͗ͨ೥ྸ͕ฦΔ" do travel_to(this_years_birthday) expect(user.age).to eq(age) end end context "஀ੜ೔Ҏલͷ৔߹" do it "஀ੜ೔લͷ೥ྸ͕ฦΔ" do travel_to(this_years_birthday.yesterday) expect(user.age).to eq(age - 1) end end travel_to ͸Ҿ਺Ͱࢦఆͨ͠೔෇ʹγεςϜ೔෇Λมߋ͢Δϝιου ςετ͢Δϝιου ςετ͢Δϝιου let(:x) { 1 } ɹ x = 1 ͸ Έ͍ͨͳΠϝʔδ ← ←ϥϯμϜʹܾ·ΔUserͷੜ೥݄೔ ←γεςϜ೔෇͔Βʮࠓ೥ʯΛऔಘʢ2022ͳͲʣ ←ಈతʹੜ੒͞ΕΔʮࠓ೥ͷ஀ੜ೔ʯ ←ಈతʹੜ੒͞ΕΔʮࠓ೥ͷ೥ྸʯ ্Ͱੜ੒ͨ͠ʮࠓ೥ͷ೥ྸʯͱageϝιουͷ໭Γ஋͕Ұக͢Δ͜ͱΛݕূ ←γεςϜ೔෇Λʮࠓ೥ͷ஀ੜ೔ͷલ೔ʯʹมߋ ্Ͱੜ੒ͨ͠ʮࠓ೥ͷ೥ྸʯΑΓ1ࡀए͘ͳΔ͜ͱΛݕূ ←γεςϜ೔෇Λʮࠓ೥ͷ஀ੜ೔ʯʹมߋ
  9. let(:user) { create(:user, birth_date: "1977/07/17".to_date) } context "஀ੜ೔Ҏ߱ͷ৔߹" do it

    "஀ੜ೔Λա͗ͨ೥ྸ͕ฦΔ" do travel_to("2022/07/17".to_date) expect(user.age).to eq(45) end end context "஀ੜ೔ΑΓҎલͷ৔߹" do it "஀ੜ೔લͷ೥ྸ͕ฦΔ" do travel_to("2022/07/16".to_date) expect(user.age).to eq(44) end end ςετ͢Δϝιου ςετ͢Δϝιου ্͔ΒԼʹಡΊΔΑ͏ʹͳͬͨ఺ʹ΋஫໨ʂ
  10. let(:user) { create(:user, birth_date: "1977/07/17".to_date) } context "஀ੜ೔Ҏ߱ͷ৔߹" do it

    "஀ੜ೔Λա͗ͨ೥ྸ͕ฦΔ" do travel_to("2022/07/17".to_date) expect(user.age).to eq(45) end end context "஀ੜ೔ΑΓҎલͷ৔߹" do it "஀ੜ೔લͷ೥ྸ͕ฦΔ" do travel_to("2022/07/16".to_date) expect(user.age).to eq(44) end end ςετ͢Δϝιου ςετ͢Δϝιου ্͔ΒԼʹಡΊΔΑ͏ʹͳͬͨ఺ʹ΋஫໨ʂ ←ੜ೥݄೔͸1977೥7݄17೔ ←γεςϜ೔෇Λ2022೥7݄17೔ͱ͢Δ ageϝιου͸ʮ45ࡀʯΛฦ͢ ←γεςϜ೔෇Λ2022೥7݄16೔ͱ͢Δ ageϝιου͸ʮ44ࡀʯΛฦ͢ ্͔ΒԼʹಡΊΔΑ͏ʹͳͬͨ఺ʹ΋஫໨ʂ
  11. &

  12. 38 ςετίʔυ͸Ұछͷ࢓༷ॻ def age today = Date.today this_years_birthday = Date.new(

    today.year, birth_date.month, birth_date.day) ret = today.year - birth_date.year if today < this_years_birthday ret -= 1 end ret end ͋ ͋ • ςετίʔυΛݟΕ͹ϝιουͷৼΔ෣͍͕͙͢Θ͔Δͷ͕ཧ૝ context "஀ੜ೔Ҏ߱ͷ৔߹" do it "஀ੜ೔Λա͗ͨ೥ྸ͕ฦΔ" do travel_to("2022/07/17".to_date) expect(user.age).to eq(45) end end context "஀ੜ೔ΑΓҎલͷ৔߹" do it "஀ੜ೔લͷ೥ྸ͕ฦΔ" do travel_to("2022/07/16".to_date) expect(user.age).to eq(44) end end RubyΛ஌Βͳ͍ਓͰ΋ςετίʔυ ͳΒΘ͔Δɺͱ͍͏ঢ়ଶΛ໨ࢦͦ͏ #
  13. 43 E2EςετͰ΋ߟ͑ํ͸ಉ͡ click_link user.name expect(page).to have_text "#{user.name}ͷ೔ه" ❌ ը໘্ͷཁૉΛม਺Ͱࢦఆ͢Δ click_link

    "͋Γ͢" expect(page).to have_text "͋Γ͢ͷ೔ه" ✅ ը໘্ͷཁૉΛϕλॻ͖Ͱࢦఆ͢Δ ม਺Λଟ༻͢ΔͱνϦπϞͰ͡Θ͡Θͱ೴಺ϝϞϦΛফඅ͠·͢……ʂʂ ※ E2Eςετ = End to Endςετɻϒϥ΢βૢ࡞ΛࣗಈԽ͠ɺγεςϜશମͷಈ࡞Λݕূ͢Δ
  14. 44 ·ͩ͋ΔϦʔμϒϧʹ͢Δίπ • ࣮ࡍͷϢʔεέʔεʹ͍ۙςετσʔλΛ࢖༻͢Δ ‣ ʮ͋͋͋ʯʮςετςετʯʮϢʔβʔ̍ʯΈ͍ͨͳςετσʔλ͸NG • describe/context/itͷઆ໌Λஸೡʹॻ͘ ‣ ʮit

    "ద੾ͳ஋Λฦ͢"ʯΈ͍ͨͳ۩ମੑͷͳ͍આ໌͸NG • ͢΂ͯͷ৘ใ͕̍ը໘ʹऩ·Δςετίʔυ͕ཧ૝ ‣ ্ԼεΫϩʔϧ͕සൟʹൃੜͨ͠ΓɺଞͷϑΝΠϧΛݟʹߦ͔ͳ͖Ό͍͚ͳ͍ͷ͸NG • DRYېࢭ͸͋͘·ͰݪଇɻదٓϝϦοτͱσϝϦοτΛఱṝʹ͔͚Δ ‣ ʮ໌֬ͳϝϦοτ͕͋ΔDRYʯ΍ʮՄಡੑΛଛͳΘͳ͍ந৅Խʯ·Ͱ์غ͢Δͷ͸NG
  15. 45 ৄ͘͠͸WebͰʂ • ʲॳ৺ऀ޲͚ʳςετίʔυͷํ਑Λߟ͑ΔʢԿΛςετ͢΂͖͔ʁͲΜͳςετΛॻ͘΂͖͔ʁʣ https://qiita.com/jnchito/items/2a5d3e15761fd413657a • ͳͥςετΛॻ͘ͷʁʢ·ͨ͸ॻ͔ͳ͍ͷʁʣ ʙςετίʔυͷ7ͭͷ໾ׂʙ https://speakerdeck.com/jnchito/number-tamarubykaigi01 •

    ςετίʔυͷظ଴஋͸DRYΛࣺͯͯϕλॻ͖͢Δ ʙςετίʔυͷॏཁͳ໾ׂͱ͸ʁʙ https://qiita.com/jnchito/items/eb3cfa9f7db752dcb796 • ๻͕RSpecͰsubjectΛ࢖Θͳ͍ཧ༝ https://blog.jnito.com/entry/2021/10/09/105651
  16. 47 ࠓ೔ͷ͓͞Β͍ subject { "ςετίʔυ" } • subject ʹ͓͍ͯɺա౓ͳDRY͸ಡΈ΍͢͞ͷఢ •

    ݡͯ͘ϩδΧϧͳ subject ΑΓɺ୭Ͱ΋ಡΊΔ۪௚ͳ subject Λʂ • ೴಺ϝϞϦΛ࢖Θͳ͍ subject ΄ͲϦʔμϒϧ • ࣮ߦՄೳͳAPIυΩϡϝϯτͩͱࢥͬͯ subject Λॻ͜͏ ͋ΕʁͳΜ͔ಡΈͮΒ͍ͳ…… subject { "foo" } ɹ subject = "foo" ※ɹɹɹɹɹɹɹɹɹɹɹ ͸ ɹɹɹɹɹɹ Έ͍ͨͳΠϝʔδ