Rails には system test (spec) と呼ばれる、Capybara を使った自動ブラウザテストの仕組みが備わっています。これはとても便利で強力なテストではありますが、けして万能ではありません。実行時間が長くなりがちですし、テストコート量も多くなりメンテナンスが大変です。
Ruby でのこのレイヤのテストの先駆けであろう Cucumber からの歴史を振り返りながら、「ちょうどよい」活用の度合いを考えたいと思います。
ͪΐ͏ͲΑ͍ 3BJMT&&ςετ #VSJ,BJHJॾڮګհ!NPSP
View Slide
‣ ࣸਅ
Kyosuke MOROHASHI@moro
4SMS?What'sSMSってなにをやってる会社なの?
https://twitter.com/sunaot/status/1002392476492038144
“情報インフラを構築することで、⾼齢社会を 取り巻く⼈びと、⾼齢社会で働く⽅や事業者の⽅、⾼齢者ご⾃⾝やそのご家族などがイキイキと ⽣活できる社会の実現を⽬指しています。— https://www.bm-sms.co.jp/philosophy/
7&
吳䒭⠓爡ؒأ٥ؒي٥ؒأ匌❨鿪庥⼒蓎Ⱅ㕦⡝♶⹛欵蓎Ⱅ㕦ةٙ٦https://www.bm-sms.co.jpؒٝآص،䱰欽؟؎زhttps://careers.bm-sms.co.jp/engineer/join us!
ͪΐ͏ͲΑ͍ 3BJMT&&ςετ
‣ ͪΐ͏ͲΑ͍&&ςετͱ‣ ͪΐ͏ͲΑ͘͢ΔͨΊͷ‣ $VDVNCFSͷ͜ͱ‣ ·ͱΊ
ͪΐ͏ͲΑ͍&&ςετͱ
ࣗಈςετॻ͍ͯ·͔͢
‣ 3BJMTతϢχοτςετ‣ PS%#ʹґଘ͠ͳ͍ϩδοΫͷςετ‣ ϦΫΤετςετ‣ γεςϜςετ‣ PS34QFDͷTQFD‣ #%%ςετ͔ɺΈ͍ͨͳͷࠓԣʹ͓͍͓͖ͯ·͢Ͷςετʹ৭Μͳछྨ͕͋Δ
‣ ࣮͢Δલ‣ ࣮ͨ͋͠ͱ‣ ͣͬͱલʹ࣮͞ΕͨίʔυʹςετΛ͍ͯ͠ΔςετΛॻ͘λΠϛϯά
‣ ։ൃΛυϥΠϒ͍ͨ͠‣ ॻ͍ͨίʔυ͕ಈ͔֬͘ೝ͍ͨ͠‣ 1VMM3FRVFTU࡞Δͷʹඞਢͱ͍͏ϧʔϧͳͷͰςετΛॻ͘ͱ͖ͷؾ࣋ͪ
‣ ςετۦಈ։ൃɺͷςετ‣ ۦಈυϥΠϒײ‣ ઌʹ͔͚Ε͍͍͚ͲɺͦΕΛڧ͍͍ͨΘ͚Ͱͳ͍‣ ͦͷͨΊͷͪΐ͏ͲΑ͍ͱ͜ΖΛ୳Δࠓͷʮςετͷతʯ
ʮͪΐ͏ͲΑ͍ʯͱ ʮ&&ςετʯͱ
‣ ։ൃΛυϥΠϒ͢Δ‣ ॻ͍ͯͯർΕͳ͍‣ ϓϩμΫτίʔυͷमਖ਼Λअຐ͠ͳ͍ͪΐ͏ͲΑ͍
‣ &OEᶃϒϥβ͔Βɺ&OEᶄಡΈॻ͖͞ΕΔ σʔλ·ͰΛશ෦ͭͳ࣮͛ͯߦ͢Δςετ‣ ݫີͳΤϯυΛܾΊΔͷ͍͠ɻ֎෦αʔϏε࿈ܞͱ͔‣ ֤ίϯϙʔωϯτ͕ɺΈ߹Θͤͨͱ͖ʹ ͪΌΜͱಈ࡞͢Δ͔Λݕূ͢Δɻ‣ 3BJMTతʹɺ4ZTUFN\5FTU 4QFD^͕֘͢Δɻ&&ΤϯυπʔΤϯυςετ
‣ Έ߹Θͤͯಈ͘͜ͱΛݕূͰ͖Δ‣ +4Ͱͭͬͨ͘6*͔Β+40/ϦΫΤετ͖͚ͨͲɺαʔόଆ3BJMTͷఆ͍ͯ͠ΔߏͱҧͬͯͨɺͳͲΛݕग़Ͱ͖Δ‣ ར༻ऀͷઢͰهड़ɾݕূͰ͖Δ‣ ෦ߏʹґଘ͠ͳ͍‣ ࣮͕ແ͍ঢ়ଶͰςετγφϦΦΛߟ͑ΒΕΔ&&ςετͷϝϦοτ
‣ ίʔυྔ͕ଟ͘ɺϝϯςφϯε͕େม‣ ը໘ͷ%0.Λͪΐͬͱม͑Δͱେྔʹࣦഊ͢Δ‣ ςετίʔυ͕େྔͰϝϯςφϯε͕ͭΒ͍‣ ࣮ߦ͕࣌ؒ͘ͳΓ͍͢‣ ಛʹ࣮ϒϥβΛಈ͔͢λΠϓ&&ςετͷσϝϦοτ
ͪΐ͏ͲΑ͍&&ςετσϝϦοτͷӨڹΛݮΒͭͭ͠ɺ ϝϦοτΛڗडͰ͖ΔΑ͏ͳ&&ςετ
ͪΐ͏ͲΑ͘͢ΔͨΊͷ
‣ ը໘ͷ%0.Λͪΐͬͱม͑Δͱେྔʹࣦഊ͢Δ‣ ςετίʔυ͕େྔͰϝϯςφϯε͕ͭΒ͍bͪΐ͏ͲΑ͞`ΛݮͣΔσϝϦοτͨͪ
‣ 3BJMTʹγεςϜςετͷΈ͕͋Δɻ‣ 34QFDͰ΄΅ಉ͡ɺ4ZTUFN4QFD͕͋Δɻ‣ όοΫΤϯυ$BQZCBSB‣ ଞݴޠͰݴ͏1VQQFUFFS ͺͯ͌͋ͳͲʹ͍ۙ‣ 4FMFOJVNΑΓߴϨϕϧ $BQZCBSBͷυϥΠόͱͯ͠4FMFOJVNΛ͑Δಓ۩ΛΖ͏
ը໘ͷ%0.Λͪΐͬͱม͑Δͱେྔʹࣦഊ͢Δ
‣ ͜͏͍͏ͷʹɺσβΠϯ߹ͰEJWΛҰݸ͚ͩ͢ͰΤϥʔʹͳΔɻঢ়css = 'form.post-wrapper > input[name="user[nickname]"]'fill_in css, with: 'moro'
‣ $BQZCBSBɺϥϕϧϓϨʔεϗϧμจݴ͔ΒJOQVUΛ୳ͤΔɻιϦϡʔγϣϯར༻ऀͷઢʹཱͭfill_in 'ニックネーム', with: 'moro'
‣ αʔϏεར༻ऀ͕ʹ͢Δͷϥϕϧ ϓϨʔεϗϧμจݴͰ͋Δ‣ ʹ͢Δͷ͕มΘͬͨΒςετ͢Δ߲มΘΔ‣ ೲಘײ͋Γ·ͤΜ ‣ MBCFMͷGPSଐੑ͕͍ͭͯͳ͍ͳͲɺ6*ͷඍόάൃݟͰ͖ͯศར‣ ܦݧ্ɺҙ֎ͱมΘΒͳ͍ϥϕϧςΩετมΘͬͨΒࣦഊ͠ͳ͍
ςετίʔυ͕େྔͰɺ ϝϯςφϯε͕ͭΒ͍
‣ ࡉ͔͍ૢ࡞Λεςοϓͣͭهड़͢Δ͜ͱͰࡶʹͳΔঢ়# ログインが必要なテストケースのたびにコピペされるvisit signup_or_signin_pathclick_on '登録済みの方はログイン'fill_in 'メールアドレス', with: '[email protected]'fill_in 'パスワード', with: 'P@ssword00!' click_on 'ログイン'
‣ ߴϨϕϧͳϔϧύʔϝιουΛ༻ҙ͢Δɻ‣ ʮϩάΠϯϑΥʔϜʹΛೖΕͯαϒϛοτʯ͔ΒʮϩάΠϯ͢Δʯͱ͍͏ؾ࣋ͪιϦϡʔγϣϯར༻ऀͷઢʹཱͭdef login_as(user)visit signup_or_singin_pathclick_on '登録済みの方はログイン'fill_in 'メールアドレス', with: user.auth.emailfill_in 'パスワード', with: COMMON_TEST_PASSWORD click_on 'ログイン'end
‣ ·ͣؾܰʹநग़͠ɺίʔυͷ༷ࢠΛݟͳ͕Βཧ͢Δ‣ ·ͣɺಉ͡ςετέʔεʹɺҙਤΛࠐΊ໊ͨલΛ͚ͭͯϝιουநग़͢Δɻ‣ ಉ͡ϑΝΠϧͷଞͷςετέʔε͔Β͍ͨ͘ͳͬͨΒɺݟ͑Δ είʔϓʹҠಈ͢Δɻ‣ ߋʹଞͷϑΝΠϧ͔Βࢀরͨ͘͠ͳͬͨΒɺڞ௨ϔϧύʔஔ͖ʹஔ͘ɻ‣ $BQZCBSB"1*·ͱΊΔ͚ͩͰͳ͘ɺநԽͷ࿙ΕΛ ہॴԽ͢ΔͨΊʹཱ͍ͭͭɺͲ͏ͬͯϔϧύʔϝιουʹ͢Δ͔
‣ ͱ͍͏Πϝʔδ͕͋Δ͕ɺҙ֎ͱͳ͍‣ ݱࡏͷࣄ3BJMTΞϓϦͰAHJUHSFQTMFFQA͕݅ͩͬͨ‣ $BQZCBSBͷߴϨϕϧϝιουΛ͏ͱɺΫϦοΫର ݕূ͢ΔςΩετ͕ݱΕΔ·ͰࣗಈͰͬͯ͘ΕΔ‣ DMJDL@POIBT@DPOUFOUͳͲɺ$BQZCBSB"1*Λ͏‣ ݪจͷهࣄ͕ͩɺߟ͑ํࠓͰ௨༻͢Δ‣ IUUQTQPTUEDDXSJUFSFMJBCMFBTZODISPOPVTJOUFHSBUJPOUFTUTXJUIDBQZCBSB൪֎+4ඇಉظॲཧͷλΠϛϯάͰࣦഊ͠TMFFQ͢Δͷ͕ۤ௧
‣ ࣮ߦ͕͔͔࣌ؒΓ͗͢Δ‣ ศར͗ͯ͢όϦσʔγϣϯͳͲςετ࢝͠Ίɺςετέʔε͕૿͑͗͢Δ‣ ֎෦ϓϩηεͱ ϒϥβͳͲͷ௨৴͕ൃੜ͢ΔͷͰͲ͏͍ͯ͠‣ ϞσϧͷϢχοτςετͰͰ͖ΔͭͦͬͪͰͬͨ΄͏͕͍͍Ͱ͢Ͷ‣ σʔληοτΞοϓ͕େมʹͳΓ͕ͪɺͱ͔‣ શ෦ͭͳ͛ΔͨΊɺσʔλҰࣜ·Δ͝ͱඞཁʹͳΓ͕ͪ‣ ݸผͷืΔ࠙ձͰͦΕҎ֎ʹ৭ʑେม͚ͩͲ
&&ςετΛͪΐ͏ͲΑ͘׆༻͢ΔιϦϡʔγϣϯར༻ऀͷઢ͔Βݟͨ ಈ͖Λهड़͠ɺݕূ͢Δ
$VDVNCFSͷ͜ͱ
‣ ࣗવݴޠͰ&&ςετΛهड़Ͱ͖ΔςεςΟϯά ϑϨʔϜϫʔΫɻ‣ $BQZCBSBͷલɺ8FCSBUͱ͍͏ϥΠϒϥϦͰ ߴϨϕϧͳ)5.-ૢ࡞"1*͕͋ͬͨɻ‣ ࣗવݴޠ͔Β$BQZCBSB8FCSBU"1*ૢ࡞ͷϚοϐϯάɺ ࣗͰهड़͢Δɻ$VDVNCFS
#langage: jaフィーチャ: ログインしてユーザーを識別できるユーザーとして、ログイン機能などで自分の情報を識別したいなぜなら、メッセージなどを「自分のもの」として区別したいからだシナリオ: ユーザ登録してログインする前提 "新規ユーザー登録"ページを表示しているもし "ログイン名"に"moro"と入力するかつ "Eメール"に"[email protected]"と入力するかつ "作成"ボタンをクリックするならば "こんにちはmoroさん"と表示されていることGiven('"{word}"に"{word}"と入力する') do |field, value|fill_in field, with: valueend
“$VDVNCFSͷΑ͏ͳπʔϧࣗવݴޠ͔Βςετίʔυͷղऍͷ͕ඞཁʹͳΔͨΊɺ͕ؒͭ૿͑ͯϝϯςφϯεੑ͕Լ͕Δͱ͍͏Πϝʔδ͕ຮԆͨͨ͠Ίɺ$VDVNCFSΛΊͯY6OJUY4QFDͰʮड͚ೖΕςετʯΛॻ͘νʔϜ૿͑·ͨ͠ɻςετۦಈ։ൃʮ$ʯΑΓ
‣ εςοϓఆٛΛ࡞ΔͷΛར༻ऀͷઢʹཱͭ ࢹมߋͷ͖͔͚ͬʹͰ͖Δͱྑ͔ͬͨ‣ ͜ͷҰ࿈ͷϑΥʔϜૢ࡞ɺͭ·ΓαʔϏεར༻ऀͱͯ͠ԿΛ͍ͯ͠Δͷ͔‣ ॳظɺ$BQZCBSBϝιουʹରԠ͢ΔཻͷεςοϓఆٛΛࣗಈੜ͠ɺ ࠞཚΛট͍ͨ ޙʹͳ͘ͳͬͨ‣ ҰาΛମݧ͢Δʹ͍͍Μ͚ͩͲɻɻɻ$VDVNCFSΛࣱΜͰ
#langage: ja...シナリオ: 新規登録後につぶやくことができる前提 ユーザー"moro"として新規登録するもし "内容"に"ブリおいしいです。"と入力するならば "ブリおいしいです。"と表示されていることかつ "つぶやき: 1件中1件"と表示されていることGiven('ユーザー"{word}"として新規登録する') do |username|fill_in 'ログイン名', with: usernamefill_in 'Eメール', with: '#{username}@example.test'click_on '新規登録'end
‣ ೲυΩϡϝϯτΛࣗಈੜ͢ΔπʔϧͰͳ͘‣ ʮड͚ೖΕςετʯ‣ ͋ͷࠒͷۭؾΈ͍ͨͳͷ࠙ձͰ‣ ར༻ऀͷࢹʹཱͬͯ αΠταʔϏεػೳͷ͍ํΛهड़͢Δπʔϧ‣ ͔͠ಈ͘&&ςετΛࣗಈԽͯ͠Կ͕͔ͨͬͨ͠ͷ͔
‣ (IFSLJOϑΥʔϚοτͰʮͳͥͳΒʯΛߟ͑Δ‣ \XIP^ͱͯ͠ɺ\IPX^͍ͨ͠ɻͳͥͳΒ\XIZ^͔ͩΒͩ‣ ϑΟʔνϟػೳ͕Ͱ͖ͨΒͲͷΑ͏ʹͳͬͯ ΄͍͔͠Λɺ͔Βग़ͯ͠ɺߟ͑Δ‣ 5%%ͷ͕ࣗ࠷ॳͷϢʔβʔͷࢹΛɺػೳશମʹద༻͢Δ‣ ͦΕΛͱʹɺιϑτΣΞ։ൃऀҎ֎ͷεςʔΫϗϧμʔͱߟ͑Λڞ༗͢Δ࣮ಈ͔ͳͯ͘ྑ͔ͬͨ
‣ ιϑτΣΞͷৼΔ͍Λɺར༻ऀͷઢʹཱͬͯهड़͢Δ͜ͱ‣ ଟ༷ͳεςʔΫϗϧμʔͱձ͢ΔͨΊɺ ͦͷͱͳΔڞ௨ޠኮΛ࡞Δ͜ͱ‣ ࣌ಉ࣌ʹྲྀߦ͍ͬͯͨ%%%͔ΒʮϢϏΩλεݴޠʯͷ֓೦Λ༌ೖ ςετۦಈ։ൃʮ$ʯπʔϧ͕มΘͬͯҾ͖ܧ͛Δͱ͍͍ͷ
‣ ར༻ऀͷઢ͔Βݟͨಈ͖Λهड़͠ɺݕূ͢Δ‣ ར༻ऀͷϝϯλϧϞσϧʹ͍ۙɺߴϨϕϧͳ"1* ޠኮΛҭ͍ͯͯ͘‣ શʹίʔυίʔυ͍ͯ͠Δ͔Β͋͠͞ΔͷͷͳͷͰ4ZTUFN\5FTU 4QFD^Ͱ
ࣗવݴޠޠኮͱίʔυޠኮΛ͚ۙͮͯΈͨྫlet(:user) { create(:user) }let(article) { create(:article) }scenario 'ヘッダメニューからマイページ行けてfav履歴に遷移できる' douser.fav(article)login_as(user)within('nav.header-nav') doclick_on 'マイページ'endclick_on 'お気に入りの記事'expect(page).to have_content(article.title)end
·ͱΊ
‣ &&ςετศརͰڧྗ͕ͩɺສೳͰͳ͍‣ յΕ͍͢‣ ίʔυྔ͕ଟ͘ͳΓ͕ͪ‣ ͪΐ͏ͲΑ͍ͱ͜ΖΛ୳Γ͍ͨ‣ ͦͷώϯτͱͳΔࢹΛ͓Ͱ͖ͯΔͱΑ͍ͷͰ͕͖͢ΐ͏ͨ͜͠ͱ
‣ ςετهड़ͷਫ४Λɺར༻ऀͷઢʹ͚ۙͮΔ‣ ͳΔ͘ߴϨϕϧ"1*Λ͏‣ ࣗͰޠኮΛҭͯΔ‣ ఆܕॲཧΛ·ͱΊͯͨΓɺϨϕϧ"1*ͷΞΫηεΛϥοϓͨ͠Γ‣ ͦ͜ʹυϝΠϯͷޠኮͰ໊લΛ͚ͭΒΕΔͱྑ͍ͪΐ͏ͲΑ͍&&ςετ