Slide 1

Slide 1 text

Ϧʔμϒϧςετίʔυ גࣜձࣾιχοΫΨʔσϯɿҏ౻३Ұ 2022-7-27 VeriServe Test Automation Talk No.3

Slide 2

Slide 2 text

https://twitter.com/jnchito/status/1552196880524013569 ͍͖ͳΓ༨ஊ ࠓ೔΄Μͱ͏ʹ͋ͬͨ࿩

Slide 3

Slide 3 text

͍͖ͳΓ༨ஊ φΠελΠϛϯάʂ!

Slide 4

Slide 4 text

5 Hello, world! " • ҏ౻ ३Ұ • גࣜձࣾιχοΫΨʔσϯͷRailsϓϩάϥϚ • ϑΟϤϧυϒʔτΩϟϯϓͷϝϯλʔ • ฌݿݝ੢࿬ࢢࡏॅʢϦϞʔτϫʔΫྺ10೥ʣ • ςετίʔυྺ 15೥Ҏ্ʢJUnit → NUnit → RSpecʣ !KODIJUP CMPHKOJUPDPN

Slide 5

Slide 5 text

6 Qiita • ϢʔβʔϥϯΩϯά1Ґʢ2022೥7݄ݱࡏʣ • QiitaදজϓϩάϥϜ །ҰͷDIAMONDड৆ऀ #

Slide 6

Slide 6 text

7 ஶॻ ʮϓϩΛ໨ࢦ͢ਓͷͨΊͷRubyೖ໳ʯ ‣ ௨শɾνΣϦʔຊ$ ‣ ग़൛ࣾɿٕज़ධ࿦ࣾ ‣ 2017೥11݄ ୈ̍൛ൃച ‣ 2021೥12݄ վగ̎൛ൃചʢRuby 3.0ʹରԠʣ 3VCZͱ5%%͕ಉ࣌ʹֶ΂·͢ʂ ͦͯ͠ʜʜ ㊗ॏ൛ग़དྷʂʢࠓ೔࿈བྷ͕དྷ·ͨ͠&ʣ ͡Ύ͏͸Μ͠Ύ͍ͬͨ

Slide 7

Slide 7 text

8 ༁ॻ ʮEveryday Rails - RSpecʹΑΔRailsςετೖ໳ʯ ‣ Aaron Sumner ஶ ‣ ग़൛ࣾɿLeanpub ‣ ిࢠॻ੶ͱͯ͠ൃചத ‣ 2014೥2݄ 1stϦϦʔε ‣ 2022೥1݄ Rails 7.0ʹରԠ 34QFDͰ3BJMTΞϓϦΛςετ ͍ͨ͠ਓ͸ͪ͜ΒΛͲ͏ͧʂ

Slide 8

Slide 8 text

9 ຊ೔͓࿩͢͠Δ͜ͱ • ςετίʔυʹ͓͍ͯɺա౓ͳDRY͸ಡΈ΍͢͞ͷఢ • ݡͯ͘ϩδΧϧͳςετίʔυΑΓɺ୭Ͱ΋ಡΊΔ۪௚ͳςετίʔυΛʂ • ೴಺ϝϞϦΛ࢖Θͳ͍ςετίʔυ΄ͲϦʔμϒϧ • ࣮ߦՄೳͳAPIυΩϡϝϯτͩͱࢥͬͯςετίʔυΛॻ͜͏ • ϓϩάϥϚ͕ࣗ෼Ͱॻ͘Ϣχοτςετͷ࿩͕ϝΠϯͰ͢

Slide 9

Slide 9 text

10 ඞཁͳࣄલ஌ࣝ • αϯϓϧίʔυ͸RSpecʢRubyʣͰॻ͖·͢ • ͕ɺςετίʔυΛॻ͍ͨܦݧ͕͋Ε͹͍͍ͩͨཧղͰ͖Δ͸ͣ • ͦ͏ɺϦʔμϒϧͳςετίʔυͳΒͶʂ • จࣈ͕খ͍͞৔߹͸ɺ͖ͬ͞πΠʔτͨ͠εϥΠυΛ։͍͍ͯͩ͘͞ if You.cannot.read_this? visit "https://speakerdeck.com/jnchito/readable-test-code-vstat" end

Slide 10

Slide 10 text

ͱ͍͏Θ͚ͰɺͦΖͦΖຊฤ΁

Slide 11

Slide 11 text

Ϧʔμϒϧςετίʔυ

Slide 12

Slide 12 text

Q. ͜Μͳܦݧ͸͋Γ·ͤΜ͔ʁ

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Α͏Θ͔ΒΜͳΒ approveͪ͠ΌμϝͰ͢'

Slide 15

Slide 15 text

https://twitter.com/jnchito/status/1539100861947064320 ͖ͬ͞ͷπΠʔτͷଓ͖

Slide 16

Slide 16 text

ςετίʔυʹ͓͍ͯɺա౓ͳ DRY͸ಡΈ΍͢͞ͷఢ DRY = Don't Repeat YourselfͷུͰίʔυ΍σʔλͷॏෳΛͳͤ͘ɺͱ͍͏ݪଇ

Slide 17

Slide 17 text

ςετίʔυʹ͓͍ͯɺա౓ͳ DRY͸ಡΈ΍͢͞ͷఢ DRY = Don't Repeat YourselfͷུͰίʔυ΍σʔλͷॏෳΛͳͤ͘ɺͱ͍͏ݪଇ ੲͷ๻Ͱ͢ ը૾͸ʮѱ॥؀ը૾δΣωϨʔλʯͰ࡞੒

Slide 18

Slide 18 text

19 Ϧʔμϒϧͳςετίʔυͷ৚݅ ✅ υΩϡϝϯτͷΑ͏ʹ্͔ΒԼʹૉ௚ʹಡΈԼͤΔ ✅ ม਺Λ࢖Θͣʹจࣈྻ΍਺஋Λϕλॻ͖͢Δ ✅ ڽͬͨςΫχοΫΛཚ༻͠ͳ͍ ❌ ϧʔϓॲཧ΍৚݅෼ذ͕සൃ͢Δʢࢹઢ্͕Լͨ͠Γδϟϯϓͨ͠Γ͢Δʣ ❌ ਺஋΍จࣈྻͷΑ͏ͳ୯७ͳσʔλ·Ͱશ෦ม਺ʹ֨ೲ͞Ε͍ͯΔ ❌ shared examples΍subjectͳͲɺςεςΟϯάFWݻ༗ͷػೳΛཚ༻͍ͯ͠Δ ൓ରʹ͢ΔͱʮಡΈʹ͍͘ςετίʔυʯͷͰ͖͕͋Γʂʂ ϑϨʔϜϫʔΫ

Slide 19

Slide 19 text

ݡͯ͘ϩδΧϧͳςετίʔυΑΓɺ ୭Ͱ΋ಡΊΔ۪௚ͳςετίʔυΛʂ ඇΤϯδχΞͰ΋ʂ

Slide 20

Slide 20 text

࣮ࡍʹૺ۰ͨ͠ςετίʔυͰઆ໌

Slide 21

Slide 21 text

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 • ࢓༷΍ϩδοΫ͸͋͑ͯઆ໌͠·ͤΜ ※ աڈʹ࣮ࡍʹίʔυϨϏϡʔͨ͠ϓϩάϥϜͱͦͷςετίʔυΛҰ෦վม͍ͯ͠·͢

Slide 22

Slide 22 text

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ϝιου͸ͲΜͳ࢓༷ʁ

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

͖ͬ͞ͷςετίʔυɺapprove͢Δʁ ✅:&4 ❌/0

Slide 25

Slide 25 text

๻͸͠·ͤΜ' ❌/0

Slide 26

Slide 26 text

ͳͥͳΒϦʔμϒϧͰ͸ͳ͍͔Β ❌/0

Slide 27

Slide 27 text

ςετίʔυͷ͔Β͘ΓΛಡΈղ͘ ⚠ ղઆ͕ඞཁͳςετίʔυʹͳͬͯΔ࣌఺Ͱͦ΋ͦ΋͓͔͍͠Αʂ

Slide 28

Slide 28 text

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 ͸Ҿ਺Ͱࢦఆͨ͠೔෇ʹγεςϜ೔෇Λมߋ͢Δϝιου ←

Slide 29

Slide 29 text

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ࡀए͘ͳΔ͜ͱΛݕূ ←γεςϜ೔෇Λʮࠓ೥ͷ஀ੜ೔ʯʹมߋ

Slide 30

Slide 30 text

……+

Slide 31

Slide 31 text

Θ͔Δ͜ͱɿ೴಺ϝϞϦΛফඅ͢Δ ςετίʔυ͸ϦʔμϒϧͰͳ͍ ࢀߟจݙɿClean Test Code Revised (by Shinichi Maeshima) https://speakerdeck.com/willnet/clean-test-code-revised

Slide 32

Slide 32 text

ͦ͜Ͱɺม਺Λͳͯ͘͠ΈΔ

Slide 33

Slide 33 text

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 ςετ͢Δϝιου ςετ͢Δϝιου ্͔ΒԼʹಡΊΔΑ͏ʹͳͬͨ఺ʹ΋஫໨ʂ

Slide 34

Slide 34 text

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ࡀʯΛฦ͢ ্͔ΒԼʹಡΊΔΑ͏ʹͳͬͨ఺ʹ΋஫໨ʂ

Slide 35

Slide 35 text

&

Slide 36

Slide 36 text

೴಺ϝϞϦͷফඅΛ཈͑Δ΄Ͳ ϦʔμϒϧͳςετίʔυʹͳΔ ࢀߟจݙɿClean Test Code Revised (by Shinichi Maeshima) https://speakerdeck.com/willnet/clean-test-code-revised

Slide 37

Slide 37 text

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Λ஌Βͳ͍ਓͰ΋ςετίʔυ ͳΒΘ͔Δɺͱ͍͏ঢ়ଶΛ໨ࢦͦ͏ #

Slide 38

Slide 38 text

39 APIυΩϡϝϯτͷαϯϓϧίʔυͱߟ͑ํ͸ಉ͡ APIυΩϡϝϯτ΋αϯϓϧίʔυ͸ϕλॻ͖͕جຊ ग़య: https://docs.ruby-lang.org/ja/latest/method/File/s/basename.html

Slide 39

Slide 39 text

40 ΋͠΋APIυΩϡϝϯτ͕ϕλॻ͖͡Όͳ͔ͬͨΒ…… ,

Slide 40

Slide 40 text

࣮ߦՄೳͳAPIυΩϡϝϯτͩͱ ࢥͬͯςετίʔυΛॻ͜͏ ςετίʔυ͸ϓϩάϥϜ ͡Όͳͯ͘υΩϡϝϯτʂ

Slide 41

Slide 41 text

ͦͷଞͷτϐοΫ

Slide 42

Slide 42 text

43 E2EςετͰ΋ߟ͑ํ͸ಉ͡ click_link user.name expect(page).to have_text "#{user.name}ͷ೔ه" ❌ ը໘্ͷཁૉΛม਺Ͱࢦఆ͢Δ click_link "͋Γ͢" expect(page).to have_text "͋Γ͢ͷ೔ه" ✅ ը໘্ͷཁૉΛϕλॻ͖Ͱࢦఆ͢Δ ม਺Λଟ༻͢ΔͱνϦπϞͰ͡Θ͡Θͱ೴಺ϝϞϦΛফඅ͠·͢……ʂʂ ※ E2Eςετ = End to Endςετɻϒϥ΢βૢ࡞ΛࣗಈԽ͠ɺγεςϜશମͷಈ࡞Λݕূ͢Δ

Slide 43

Slide 43 text

44 ·ͩ͋ΔϦʔμϒϧʹ͢Δίπ • ࣮ࡍͷϢʔεέʔεʹ͍ۙςετσʔλΛ࢖༻͢Δ ‣ ʮ͋͋͋ʯʮςετςετʯʮϢʔβʔ̍ʯΈ͍ͨͳςετσʔλ͸NG • describe/context/itͷઆ໌Λஸೡʹॻ͘ ‣ ʮit "ద੾ͳ஋Λฦ͢"ʯΈ͍ͨͳ۩ମੑͷͳ͍આ໌͸NG • ͢΂ͯͷ৘ใ͕̍ը໘ʹऩ·Δςετίʔυ͕ཧ૝ ‣ ্ԼεΫϩʔϧ͕සൟʹൃੜͨ͠ΓɺଞͷϑΝΠϧΛݟʹߦ͔ͳ͖Ό͍͚ͳ͍ͷ͸NG • DRYېࢭ͸͋͘·ͰݪଇɻదٓϝϦοτͱσϝϦοτΛఱṝʹ͔͚Δ ‣ ʮ໌֬ͳϝϦοτ͕͋ΔDRYʯ΍ʮՄಡੑΛଛͳΘͳ͍ந৅Խʯ·Ͱ์غ͢Δͷ͸NG

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

·ͱΊ

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

͓ͬͱɺ͍͢·ͤΜʂ ͍ͭɺDRYʹॻ͖ͨ͘ͳΔΫη͕-

Slide 48

Slide 48 text

ͪΌΜͱϕλॻ͖͠·͢.

Slide 49

Slide 49 text

50 ࠓ೔ͷ͓͞Β͍ • ςετίʔυʹ͓͍ͯɺա౓ͳDRY͸ಡΈ΍͢͞ͷఢ • ݡͯ͘ϩδΧϧͳςετίʔυΑΓɺ୭Ͱ΋ಡΊΔ۪௚ͳςετίʔυΛʂ • ೴಺ϝϞϦΛ࢖Θͳ͍ςετίʔυ΄ͲϦʔμϒϧ • ࣮ߦՄೳͳAPIυΩϡϝϯτͩͱࢥͬͯςετίʔυΛॻ͜͏

Slide 50

Slide 50 text

https://twitter.com/jnchito/status/1539100857991852032 ࠶ܝʢ2ճ໨ʣ

Slide 51

Slide 51 text

ϦʔμϒϧͳςετίʔυΛॻ͍ͯ ࣗ৴Λ΋ͬͯϤγʂͯ͠΋Β͍·͠ΐ͏ -(5. jnchito

Slide 52

Slide 52 text

͝ਗ਼ௌ !KODIJUP CMPHKOJUPDPN ɹɹɹ͋Γ͕ͱ͏͍͟͝·ͨ͠