ちょうどよい Rails E2E テスト/enough-good-rails-e2e-test

ちょうどよい Rails E2E テスト/enough-good-rails-e2e-test

Rails には system test (spec) と呼ばれる、Capybara を使った自動ブラウザテストの仕組みが備わっています。これはとても便利で強力なテストではありますが、けして万能ではありません。実行時間が長くなりがちですし、テストコート量も多くなりメンテナンスが大変です。

Ruby でのこのレイヤのテストの先駆けであろう Cucumber からの歴史を振り返りながら、「ちょうどよい」活用の度合いを考えたいと思います。

70e13d9877054026fda46d5a5b53a236?s=128

MOROHASHI Kyosuke

February 01, 2020
Tweet

Transcript

  1. ͪΐ͏ͲΑ͍
 3BJMT&&ςετ 
 #VSJ,BJHJ ॾڮګհ!NPSP 

  2. ‣ ࣸਅ 

  3.  Kyosuke MOROHASHI @moro

  4. 4 SMS? What's SMSってなにをやってる会社なの?

  5.  https://twitter.com/sunaot/status/1002392476492038144

  6. “ 情報インフラを構築することで、⾼齢社会を
 取り巻く⼈びと、⾼齢社会で働く⽅や事業者の⽅、 ⾼齢者ご⾃⾝やそのご家族などがイキイキと
 ⽣活できる社会の実現を⽬指しています。 — https://www.bm-sms.co.jp/philosophy/

  7. 7 &

  8. 吳䒭⠓爡ؒأ ٥ ؒي ٥ ؒأ 匌❨鿪庥⼒蓎Ⱅ㕦⡝⿼♶⹛欵蓎Ⱅ㕦ةٙ٦ https://www.bm-sms.co.jp ؒٝآص،䱰欽؟؎ ز https://careers.bm-sms.co.jp/engineer/

    join us!
  9. ͪΐ͏ͲΑ͍
 3BJMT&&ςετ 

  10. ‣ ͪΐ͏ͲΑ͍&&ςετͱ͸ ‣ ͪΐ͏ͲΑ͘͢ΔͨΊͷ޻෉ ‣ $VDVNCFSͷ͜ͱ ‣ ·ͱΊ 

  11. ͪΐ͏ͲΑ͍&&ςετͱ͸ 

  12. ࣗಈςετॻ͍ͯ·͔͢ 

  13. ‣ 3BJMTతϢχοτςετ ‣ PS%#ʹ΋ґଘ͠ͳ͍ϩδοΫͷςετ  ‣ ϦΫΤετςετ ‣ γεςϜςετ ‣

    PS34QFDͷ TQFD ‣ #%%͸ςετ͔ɺΈ͍ͨͳͷ࿩͸ࠓ೔͸ԣʹ͓͍͓͖ͯ·͢Ͷ ςετʹ΋৭Μͳछྨ͕͋Δ 
  14. ‣ ࣮૷͢Δલ ‣ ࣮૷ͨ͋͠ͱ ‣ ͣͬͱલʹ࣮૷͞ΕͨίʔυʹςετΛ଍͍ͯ͠Δ ςετΛॻ͘λΠϛϯά 

  15. ‣ ։ൃΛυϥΠϒ͍ͨ͠ ‣ ॻ͍ͨίʔυ͕ಈ͔֬͘ೝ͍ͨ͠ ‣ 1VMM3FRVFTU࡞Δͷʹඞਢͱ͍͏ϧʔϧͳͷͰ ςετΛॻ͘ͱ͖ͷؾ࣋ͪ 

  16. ‣ ςετۦಈ։ൃɺͷςετ ‣ ۦಈυϥΠϒײ ‣ ઌʹ͔͚Ε͹͍͍͚ͲɺͦΕΛڧ͍͍ͨΘ͚Ͱ͸ͳ͍ ‣ ͦͷͨΊͷͪΐ͏ͲΑ͍ͱ͜ΖΛ୳Δ ࠓ೔ͷʮςετͷ໨తʯ 

  17. ʮͪΐ͏ͲΑ͍ʯͱ͸ 
 ʮ&&ςετʯͱ͸ 

  18. ‣ ։ൃΛυϥΠϒ͢Δ ‣ ॻ͍ͯͯർΕͳ͍ ‣ ϓϩμΫτίʔυͷमਖ਼Λअຐ͠ͳ͍ ͪΐ͏ͲΑ͍ 

  19. ‣ &OEᶃϒϥ΢β͔Βɺ&OEᶄಡΈॻ͖͞ΕΔ
 σʔλ·ͰΛશ෦ͭͳ࣮͛ͯߦ͢Δςετ ‣ ݫີͳΤϯυΛܾΊΔͷ͸೉͍͠ɻ֎෦αʔϏε࿈ܞͱ͔ ‣ ֤ίϯϙʔωϯτ͕ɺ૊Έ߹Θͤͨͱ͖ʹ
 ͪΌΜͱಈ࡞͢Δ͔Λݕূ͢Δɻ ‣ 3BJMTతʹ͸ɺ4ZTUFN\5FTU

    4QFD^͕֘౰͢Δɻ &&ΤϯυπʔΤϯυςετ 
  20. ‣ ૊Έ߹Θͤͯಈ͘͜ͱΛݕূͰ͖Δ ‣ +4Ͱͭͬͨ͘6*͔Β+40/ϦΫΤετ͖͚ͨͲɺαʔόଆ3BJMTͷ૝ఆ͍ͯ͠Δ ߏ଄ͱҧͬͯͨɺͳͲΛݕग़Ͱ͖Δ ‣ ར༻ऀͷ໨ઢͰهड़ɾݕূͰ͖Δ ‣ ಺෦ߏ଄ʹґଘ͠ͳ͍ ‣

    ࣮૷͕ແ͍ঢ়ଶͰ΋ςετγφϦΦΛߟ͑ΒΕΔ &&ςετͷϝϦοτ 
  21. ‣ ίʔυྔ͕ଟ͘ɺϝϯςφϯε͕େม ‣ ը໘ͷ%0.Λͪΐͬͱม͑Δͱେྔʹࣦഊ͢Δ ‣ ςετίʔυ͕େྔͰϝϯςφϯε͕ͭΒ͍ ‣ ࣮ߦ͕࣌ؒ௕͘ͳΓ΍͍͢ ‣ ಛʹ࣮ϒϥ΢βΛಈ͔͢λΠϓ

    &&ςετͷσϝϦοτ 
  22. ͪΐ͏ͲΑ͍&&ςετ σϝϦοτͷӨڹΛݮΒͭͭ͠ɺ
 ϝϦοτΛڗडͰ͖ΔΑ͏ͳ&&ςετ 

  23. ͪΐ͏ͲΑ͘͢ΔͨΊͷ޻෉

  24. ‣ ը໘ͷ%0.Λͪΐͬͱม͑Δͱେྔʹࣦഊ͢Δ ‣ ςετίʔυ͕େྔͰϝϯςφϯε͕ͭΒ͍ bͪΐ͏ͲΑ͞`ΛݮͣΔσϝϦοτͨͪ 

  25. ‣ 3BJMTʹ͸γεςϜςετͷ࢓૊Έ͕͋Δɻ ‣ 34QFDͰ΋΄΅ಉ͡ɺ4ZTUFN4QFD͕͋Δɻ ‣ όοΫΤϯυ͸$BQZCBSB ‣ ଞݴޠͰݴ͏1VQQFUFFS ͺ΃ͯ͌͋ ͳͲʹ͍ۙ

    ‣ 4FMFOJVNΑΓߴϨϕϧ $BQZCBSBͷυϥΠόͱͯ͠4FMFOJVNΛ࢖͑Δ ಓ۩Λ஌Ζ͏ 
  26. ը໘ͷ%0.Λͪΐͬͱ ม͑Δͱେྔʹࣦഊ͢Δ 

  27. ‣ ͜͏͍͏ͷʹɺσβΠϯ౎߹ͰEJWΛҰݸ଍͚ͩ͢Ͱ ΤϥʔʹͳΔɻ ঱ঢ়  css = 'form.post-wrapper > input[name="user[nickname]"]'

    fill_in css, with: 'moro'
  28. ‣ $BQZCBSB͸ɺϥϕϧ΍ϓϨʔεϗϧμจݴ͔Β JOQVUΛ୳ͤΔɻ ιϦϡʔγϣϯར༻ऀͷ໨ઢʹཱͭ  fill_in 'ニックネーム', with: 'moro'

  29. ‣ αʔϏεར༻ऀ͕໨ʹ͢Δ΋ͷ͸ϥϕϧ΍
 ϓϨʔεϗϧμจݴͰ͋Δ ‣ ໨ʹ͢Δ΋ͷ͕มΘͬͨΒςετ͢Δ߲໨΋มΘΔ ‣ ೲಘײ͋Γ·ͤΜ  ‣ MBCFMͷGPSଐੑ͕͍ͭͯͳ͍ͳͲɺ6*ͷඍόάൃݟͰ͖ͯศར

    ‣ ܦݧ্ɺҙ֎ͱมΘΒͳ͍ ϥϕϧςΩετมΘͬͨΒࣦഊ͠ͳ͍ 
  30. ςετίʔυ͕େྔͰɺ
 ϝϯςφϯε͕ͭΒ͍ 

  31. ‣ ࡉ͔͍ૢ࡞Λεςοϓͣͭهड़͢Δ͜ͱͰ൥ࡶʹͳΔ ঱ঢ়  # ログインが必要なテストケースのたびにコピペされる visit signup_or_signin_path click_on '登録済みの方はログイン'

    fill_in 'メールアドレス', with: 'moro@example.test' fill_in 'パスワード', with: 'P@ssword00!' 
 click_on 'ログイン'
  32. ‣ ߴϨϕϧͳϔϧύʔϝιουΛ༻ҙ͢Δɻ ‣ ʮϩάΠϯϑΥʔϜʹ஋ΛೖΕͯαϒϛοτʯ͔ΒʮϩάΠϯ͢Δʯͱ͍͏ؾ࣋ͪ ιϦϡʔγϣϯར༻ऀͷ໨ઢʹཱͭ  def login_as(user) visit signup_or_singin_path

    click_on '登録済みの方はログイン' fill_in 'メールアドレス', with: user.auth.email fill_in 'パスワード', with: COMMON_TEST_PASSWORD 
 click_on 'ログイン' end
  33. ‣ ·ͣ͸ؾܰʹநग़͠ɺίʔυͷ༷ࢠΛݟͳ͕Β੔ཧ͢Δ ‣ ·ͣ͸ɺಉ͡ςετέʔε಺ʹɺҙਤΛࠐΊ໊ͨલΛ͚ͭͯϝιουநग़͢Δɻ ‣ ಉ͡ϑΝΠϧͷଞͷςετέʔε͔Β΋࢖͍ͨ͘ͳͬͨΒɺݟ͑Δ
 είʔϓʹҠಈ͢Δɻ ‣ ߋʹଞͷϑΝΠϧ͔Β΋ࢀরͨ͘͠ͳͬͨΒɺڞ௨ϔϧύʔஔ͖৔ʹஔ͘ɻ ‣

    $BQZCBSB"1*·ͱΊΔ͚ͩͰͳ͘ɺந৅Խͷ࿙ΕΛ
 ہॴԽ͢ΔͨΊʹ΋໾ཱͭ ͍ͭɺͲ͏΍ͬͯϔϧύʔϝιουʹ͢Δ͔ 
  34. ‣ ͱ͍͏Πϝʔδ͕͋Δ͕ɺҙ֎ͱͳ͍ ‣ ݱࡏͷ࢓ࣄ3BJMTΞϓϦͰ΋AHJUHSFQTMFFQA͕݅ͩͬͨ ‣ $BQZCBSBͷߴϨϕϧϝιουΛ࢖͏ͱɺΫϦοΫର৅΍
 ݕূ͢ΔςΩετ͕ݱΕΔ·ͰࣗಈͰ଴ͬͯ͘ΕΔ ‣ DMJDL@PO΍IBT@DPOUFOUͳͲɺ$BQZCBSB"1*Λ࢖͏ ‣

    ೥ ݪจ೥ ͷهࣄ͕ͩɺߟ͑ํ͸ࠓͰ΋௨༻͢Δ ‣ IUUQTQPTUEDDXSJUFSFMJBCMFBTZODISPOPVTJOUFHSBUJPOUFTUTXJUIDBQZCBSB ൪֎+4ඇಉظॲཧͷλΠϛϯάͰࣦഊ͠TMFFQ͢Δͷ͕ۤ௧ 
  35. ‣ ࣮ߦ͕͔͔࣌ؒΓ͗͢Δ ‣ ศར͗ͯ͢όϦσʔγϣϯͳͲ΋ςετ࢝͠Ίɺςετέʔε͕૿͑͗͢Δ ‣ ֎෦ϓϩηεͱ ϒϥ΢βͳͲ ͷ௨৴͕ൃੜ͢ΔͷͰͲ͏ͯ͠΋஗͍ ‣ ϞσϧͷϢχοτςετͰͰ͖Δ΍ͭ͸ͦͬͪͰ΍ͬͨ΄͏͕͍͍Ͱ͢Ͷ

    ‣ σʔληοτΞοϓ͕େมʹͳΓ͕ͪɺͱ͔ ‣ શ෦ͭͳ͛ΔͨΊɺσʔλҰࣜ·Δ͝ͱඞཁʹͳΓ͕ͪ ‣ ݸผͷืΔ࿩͸࠙਌ձͰ ͦΕҎ֎ʹ΋৭ʑେม͚ͩͲ 
  36. &&ςετΛͪΐ͏ͲΑ͘׆༻͢ΔιϦϡʔγϣϯ ར༻ऀͷ໨ઢ͔Βݟͨ
 ಈ͖Λهड़͠ɺݕূ͢Δ 

  37. $VDVNCFSͷ͜ͱ

  38. ‣ ࣗવݴޠͰ&&ςετΛهड़Ͱ͖ΔςεςΟϯά
 ϑϨʔϜϫʔΫɻ ‣ $BQZCBSBͷલ਎ɺ8FCSBUͱ͍͏ϥΠϒϥϦͰ
 ߴϨϕϧͳ)5.-ૢ࡞"1*͕͋ͬͨɻ ‣ ࣗવݴޠ͔Β$BQZCBSB8FCSBU"1*ૢ࡞ͷϚοϐϯά͸ɺ
 ࣗ෼Ͱهड़͢Δɻ $VDVNCFS

    
  39. 

  40.  #langage: ja フィーチャ: ログインしてユーザーを識別できる ユーザーとして、 ログイン機能などで自分の情報を識別したい なぜなら、メッセージなどを「自分のもの」として区別したいからだ シナリオ: ユーザ登録してログインする

    前提 "新規ユーザー登録"ページを表示している もし "ログイン名"に"moro"と入力する かつ "Eメール"に"moro@example.test"と入力する かつ "作成"ボタンをクリックする ならば "こんにちはmoroさん"と表示されていること Given('"{word}"に"{word}"と入力する') do |field, value| fill_in field, with: value end
  41. “ $VDVNCFSͷΑ͏ͳπʔϧ͸ࣗવݴޠ͔Βςετ ίʔυ΁ͷղऍͷ૚͕ඞཁʹͳΔͨΊɺؒ઀૚͕ͭ ૿͑ͯϝϯςφϯεੑ͕Լ͕Δͱ͍͏Πϝʔδ͕ຮ Ԇͨͨ͠Ίɺ$VDVNCFSΛ΍ΊͯY6OJUY4QFDͰ ʮड͚ೖΕςετʯΛॻ͘νʔϜ΋૿͑·ͨ͠ɻ ςετۦಈ։ൃʮ෇࿥$ʯΑΓ

  42. ‣ εςοϓఆٛΛ࡞ΔͷΛར༻ऀͷ໨ઢʹཱͭ
 ࢹ఺มߋͷ͖͔͚ͬʹͰ͖Δͱྑ͔ͬͨ ‣ ͜ͷҰ࿈ͷϑΥʔϜૢ࡞͸ɺͭ·ΓαʔϏεར༻ऀͱͯ͠ԿΛ͍ͯ͠Δͷ͔ ‣ ॳظ͸ɺ$BQZCBSBϝιουʹରԠ͢Δཻ౓ͷεςοϓఆٛΛࣗಈੜ੒͠ɺ
 ࠞཚΛট͍ͨ ޙʹͳ͘ͳͬͨ 

    ‣ Ұา໨Λମݧ͢Δʹ͸͍͍Μ͚ͩͲɻɻɻ $VDVNCFSΛࣱΜͰ 
  43.  #langage: ja ... シナリオ: 新規登録後につぶやくことができる 前提 ユーザー"moro"として新規登録する もし "内容"に"ブリおいしいです。"と入力する

    ならば "ブリおいしいです。"と表示されていること かつ "つぶやき: 1件中1件"と表示されていること Given('ユーザー"{word}"として新規登録する') do |username| fill_in 'ログイン名', with: username fill_in 'Eメール', with: '#{username}@example.test' click_on '新規登録' end
  44. ‣ ೲ඼υΩϡϝϯτΛࣗಈੜ੒͢ΔπʔϧͰ͸ͳ͘ ‣ ʮड͚ೖΕςετʯ ‣ ͋ͷࠒͷۭؾΈ͍ͨͳͷ͸࠙਌ձͰ ‣ ར༻ऀͷࢹ఺ʹཱͬͯ
 αΠτ΍αʔϏε΍ػೳͷ࢖͍ํΛهड़͢Δπʔϧ ‣

    ͔͠΋ಈ͘ &&ςετΛࣗಈԽͯ͠Կ͕͔ͨͬͨ͠ͷ͔ 
  45. ‣ (IFSLJOϑΥʔϚοτͰʮͳͥͳΒʯΛߟ͑Δ ‣ \XIP^ͱͯ͠ɺ\IPX^͍ͨ͠ɻͳͥͳΒ\XIZ^͔ͩΒͩ ‣ ϑΟʔνϟػೳ͕Ͱ͖ͨΒͲͷΑ͏ʹͳͬͯ
 ΄͍͔͠Λɺ೴಺͔Βग़ͯ͠ɺߟ͑Δ ‣ 5%%ͷࣗ෼͕࠷ॳͷϢʔβʔͷࢹ఺Λɺػೳશମʹద༻͢Δ ‣

    ͦΕΛ΋ͱʹɺιϑτ΢ΣΞ։ൃऀҎ֎ͷεςʔΫϗϧ μʔͱ΋ߟ͑Λڞ༗͢Δ ࣮͸ಈ͔ͳͯ͘΋ྑ͔ͬͨ 
  46. ‣ ιϑτ΢ΣΞͷৼΔ෣͍Λɺར༻ऀͷ໨ઢʹཱͬͯ هड़͢Δ͜ͱ ‣ ଟ༷ͳεςʔΫϗϧμʔͱձ࿩͢ΔͨΊɺ
 ͦͷ౔୆ͱͳΔڞ௨ޠኮΛ࡞Δ͜ͱ ‣ ౰࣌ಉ࣌ʹྲྀߦ͍ͬͯͨ%%%͔ΒʮϢϏΩλεݴޠʯͷ֓೦Λ༌ೖ
 ςετۦಈ։ൃʮ෇࿥$ʯ πʔϧ͕มΘͬͯ΋Ҿ͖ܧ͛Δͱ͍͍΋ͷ

    
  47. ‣ ར༻ऀͷ໨ઢ͔Βݟͨಈ͖Λهड़͠ɺݕূ͢Δ ‣ ར༻ऀͷϝϯλϧϞσϧʹ͍ۙɺߴϨϕϧͳ"1*
 ޠኮ Λҭ͍ͯͯ͘ ‣ ׬શʹίʔυίʔυ͍ͯ͠Δ͔Β೉͠͞͸͋Δ΋ͷͷ ͳͷͰ4ZTUFN\5FTU 4QFD^Ͱ΋

    
  48. ࣗવݴޠޠኮͱίʔυޠኮΛ͚ۙͮͯΈͨྫ  let(:user) { create(:user) } let(article) { create(:article) }

    scenario 'ヘッダメニューからマイページ行けてfav履歴に遷移できる' do user.fav(article) login_as(user) within('nav.header-nav') do click_on 'マイページ' end click_on 'お気に入りの記事' expect(page).to have_content(article.title) end
  49. ·ͱΊ

  50. ‣ &&ςετ͸ศརͰڧྗ͕ͩɺສೳͰ͸ͳ͍ ‣ յΕ΍͍͢ ‣ ίʔυྔ͕ଟ͘ͳΓ͕ͪ ‣ ͪΐ͏ͲΑ͍ͱ͜ΖΛ୳Γ͍ͨ ‣ ͦͷώϯτͱͳΔࢹ఺Λ͓࿩Ͱ͖ͯΔͱΑ͍ͷͰ͕͢

    ͖ΐ͏࿩ͨ͜͠ͱ 
  51. ‣ ςετهड़ͷਫ४Λɺར༻ऀͷ໨ઢʹ͚ۙͮΔ ‣ ͳΔ΂͘ߴϨϕϧ"1*Λ࢖͏ ‣ ࣗ෼Ͱ΋ޠኮΛҭͯΔ ‣ ఆܕॲཧΛ·ͱΊͯͨΓɺ௿Ϩϕϧ"1*΁ͷΞΫηεΛϥοϓͨ͠Γ ‣ ͦ͜ʹυϝΠϯͷޠኮͰ໊લΛ͚ͭΒΕΔͱྑ͍

    ͪΐ͏ͲΑ͍&&ςετ