Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
コンテキストとセマンティクスを意識してリーダブルなE2Eテストコードを書こう
Search
tsuemura
July 27, 2022
Technology
12
30k
コンテキストとセマンティクスを意識してリーダブルなE2Eテストコードを書こう
リーダブルなテストコードについて考えよう ~VeriServe Test Automation Talk No.3~ 2022-07-27 での講演スライドです。
tsuemura
July 27, 2022
Tweet
Share
More Decks by tsuemura
See All by tsuemura
自分の軸足を見つけろ
tsuemura
3
1.5k
事業継続を支える自動テストの考え方
tsuemura
0
1.4k
テスト自動化ことはじめ(202412_オープンロジ版) / Enter the testing automation (2024 Dec, for OPENLOGI)
tsuemura
0
1.6k
E2Eテストのシナリオと抽象化の粒度の話.pdf
tsuemura
6
1.2k
テスト自動化ことはじめ
tsuemura
3
580
ようこそ、ソフトウェアテストの世界へ!
tsuemura
1
150
リーダブルなE2Eテストコードのための3つのC
tsuemura
7
1.2k
60分で学ぶE2Eテスト(実装編)
tsuemura
0
460
全部乗せフレームワーク CodeceptJS でE2Eテストを楽にしよう
tsuemura
7
5.6k
Other Decks in Technology
See All in Technology
AIエージェント時代に備える AWS Organizations とアカウント設計
kossykinto
3
630
型を書かないRuby開発への挑戦
riseshia
0
210
20260311 ビジネスSWG活動報告(デジタルアイデンティティ人材育成推進WG Ph2 活動報告会)
oidfj
0
160
Oracle Database@Google Cloud:サービス概要のご紹介
oracle4engineer
PRO
5
1.1k
[JAWSDAYS2026][D8]その起票、愛が足りてますか?AWSサポートを味方につける、技術的「ラブレター」の書き方
hirosys_
3
110
DevOpsエージェントで実現する!! AWS Well-Architected(W-A) を実現するシステム設計 / 20260307 Masaki Okuda
shift_evolve
PRO
3
450
AWS DevOps Agent vs SRE俺 / AWS DevOps Agent vs me, the SRE
sms_tech
3
510
Kaggleの経験が実務にどう活きているか / kaggle_findy
sansan_randd
7
1.3k
LINE Messengerの次世代ストレージ選定
lycorptech_jp
PRO
19
7.7k
ナレッジワークのご紹介(第88回情報処理学会 )
kworkdev
PRO
0
160
越境する組織づくり ─ 多様性を前提にしたチームビルディングとリードの実践知
kido_engineer
2
170
20260305_【白金鉱業】分析者が地理情報を武器にするための軽量なアドホック分析環境
yucho147
2
220
Featured
See All Featured
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
390
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
0
150
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.2k
How to train your dragon (web standard)
notwaldorf
97
6.5k
Skip the Path - Find Your Career Trail
mkilby
1
75
Marketing to machines
jonoalderson
1
5k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
2
980
Fireside Chat
paigeccino
42
3.8k
Building a Scalable Design System with Sketch
lauravandoore
463
34k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
150
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
140
Transcript
コンテキストとセマンティクスを意識して リーダブルなE2Eテストコードを書こう Takuya Suemura @ Autify, Inc. リーダブルなテストコードについて考えよう ~VeriServe Test
Automation Talk No.3~ 2022-07-27
おれは誰だぜ 末村 拓也 開発者、フィールドエンジニア、QAなどを経て、2019年にAutifyに入社。 自動テスト、特にWebのE2Eテストに強い。 現職ではテクニカルサポートを担当。テスト対象とテストフレームワークの互換性の 問題などを調査、解決する役割を担う。 テトリスが好き。
おれが今まで話してきたこと JaSST'22 Tokyo 60分で学ぶE2Eテスト (ベリサーブ 伊藤由貴さんと共演) https://github.com/tsuemura/jasst22-tokyo JTF2020 テストを自動化するのをやめ、自動テストを作ろう https://speakerdeck.com/tsuemura/tesutowozi-dong-hua-surufalsewoyame-zi-
dong-tesutowozuo-rou 「E2Eテストとはなにか」「理想的なE2Eテストの書き方とは」を ひたすら考えたり話したりし続けている人です
今日話すこと そもそもE2Eテストってどういうものだっけ? E2Eテストをリーダブルにする理由は? どうやってリーダブルにするの?
そもそもE2Eテストとは
よくあるE2Eテストのイメージ ブラウザとかモバイルデバイスを自動操作して WebアプリとかモバイルアプリのUIを ユーザーが操作するのと同じようにテストする
None
(Webの) E2Eテストで用いられる技術 Webブラウザの自動操作技術 Selenium, Cypress, PlayWright etc. 要素特定の手段 CSS Selector,
XPath etc.
E2Eテストの例 Cypressによる擬似コード /** ログインする **/ // メールアドレスを入力 cy.type('input[name=email]', '
[email protected]
') //
パスワードを入力 cy.type('input[name=password]', 'pass1234') // 送信ボタンをクリック cy.click('input[type=submit]') この例では CSSセレクタ で要素を特定し、 それらをクリックしたり、文字を入力したりしている
E2Eテストをリーダブルにする理由は?
E2Eテストをリーダブルにする理由は? =(脳の)メモリの無駄遣いを防ぐ E2Eテストコードは次のようなことを 想像 しながら読まないといけない 長いテストコードを最初から読みながら 今どのページにいるのか想像しながら どのボタンを押しているのか想像しながら 想像をなるべく減らす のがポイント
読みにくいUI操作の例 // 送信ボタン cy.get('button[type="submit"]').click() // 「OK 」ボタン cy.get('button.primary').click() どちらも CSSセレクタ
を用いて要素を探索しているが…… type="submit" が送信ボタンであることを知っているのは エンジニアだけ primary クラスがOKボタンに当たってるのは ただの実装上の都合 ユーザーは type="submit" や .primary のような内部的な属性値を使わず、 ラ ベル で探す 読みにくいだけでなく、ユーザー目線でもないので、誰の得にもならない
読みにくいシナリオの例 // メールアドレスを入力 cy.get('input[name="email"]').type('
[email protected]
') // パスワードを入力 cy.get('input[name="password"]').type('pass1234') // 送信ボタンをクリック cy.get('button[type="submit"]').click()
このページは ログイン ? それとも 新規登録 ?
読みにくいシナリオの例 // 新規登録ページにアクセス cy.visit('/register') // メールアドレスを入力 cy.get('input[name="email"]').type('
[email protected]
') // パスワードを入力 cy.get('input[name="password"]').type('pass1234')
// 送信ボタンをクリック cy.get('button[type="submit"]').click() 直前で「新規登録ページにアクセスした」という 文脈 が無いと読み解けない
ここまでのまとめ 想像で読む部分を減らしたい、そのために ユーザーが要素を探すときと同じ方法で要素を探したい 文脈に依存する書き方を減らしたい
どうやってリーダブルにするの?
どうやってリーダブルにするの? セマンティックな書き方を用いる ユーザーにとって意味のある書き方を用いる コンテキストを明示する 「今何をしているのか」「今どこにいるのか」を明確にする
読みにくいUI操作の例(おさらい) // 送信ボタン cy.get('button[type="submit"]').click() // 「OK 」ボタン cy.get('button.primary').click() どちらも サイトの内部構造
を用いて要素を探索しており ユーザー目線 ではない 意味のある = セマンティックな書き方 を使おう
セマンティックな書き方の例 1. 文言を用いる 2. サイトのアクセシビリティを用いる
1. 文言を用いる Cypress では文言を用いたセレクタを使える 以下の例では Sign Up という文言を含む要素をクリックする cy.contains('Sign Up').click()
※ 複数見つかった場合、一番最初に見つかった要素をクリックしてしまうので注意
文言だけでは出来ないケースはどうしたら? 例: ハンバーガーメニューのアイコン 例: あるラベルを持つ入力フォーム 例: 画像
Testing Library を使ってみよう Testing Library 要素の 役割 や ラベル などを用いてテストコードを書くためのライブラリ
// 例 getByRole("textbox", {name: / メールアドレス/})
Testing Library を使わない場合 // span タグを用いて作成した擬似的な Submit ボタン <span role="button">Submit</span>
// button タグを用いて作成した Submit ボタン <button>Submit</button> この2つは button という role と Submit という name を持つ 意味的にはほぼ等価だが テストフレームワークからは異なるセレクタを使わなければいけない cy.get('span').contain('Submit') cy.get('button').contain('Submit')
Testing Library を使う場合 Testing Library を使うとどちらも同じ形で書ける getByRole("button", {name: /Submit/})
アクセシビリティの高いサイトはテスタビリティも高い Testing Library は アクセシビリティ を用いてテストしている つまり、これら3つがシームレスに実現できる 開発者: アクセシビリティ改善 QA:
アクセシビリティ特性を用いたユーザー目線でのE2Eテスト ユーザー: アクセシビリティの利用 テスターにとってのアクセシビリティの優先度は実は高い テストしにくいサイトがあったときに、 「テストしやすく」ではなく「アクセスしやすく」という提案が出来るかも
どうやって使うの? Testing Library は Cypress, Puppeteer, TestCafe, PlayWrightなど主要なテストフレ ームワークに対応 簡単に試したいならChrome拡張
Testing Playground を使おう
コンテキストを明示する
コンテキストを明示する 読みにくいシナリオの例(おさらい) // メールアドレスを入力 cy.get('input[name="email"]').type('
[email protected]
') // パスワードを入力 cy.get('input[name="password"]').type('pass1234') // 送信ボタンをクリック
cy.get('button[type="submit"]').click() このページは ログイン ? それとも 新規登録 ?
コンテキストを明示する手法 1. Page Object 2. Context Enclosure
Page Object Pattern の利用 ページ内のロケーター、ページ特有の操作などをオブジェクトにまとめるテクニック 本来はメンテナンス性向上のための技だが、副次的にコンテキストを明示することも 出来る const loginPage =
new LoginPage() loginPage.getEmailInput().type('
[email protected]
') loginPage.getPasswordInput().type('pass1234') loginPage.getSubmitButton().click() どのUI要素も loginPage という Page Object のインスタンスから生えている = ログインページ内の要素であることが明示的に示されている
Page Object の実装例 class LoginPage { getEmailInput() { return cy.get('input[name="email"]')
} getPasswordInput() { return cy.get('input[name="password"]') } getSubmitButton() { return cy.get('button[type="submit"]') } } ログインページ内の要素をあらかじめ PageObject 内に定義する
Page Object は結構手間がかかる 例えば、ログインページに Remember me? という チェックボックスを追加したが、Page Objectには追加していないとする const
loginPage = new LoginPage() loginPage.getEmailInput().type('
[email protected]
') loginPage.getPasswordInput().type('pass1234') cy.contains('Remember me?').check() // ここだけ loginPage に属してないように見える loginPage.getSubmitButton().click() 要素を追加した際、かならず Page Object に要素を登録する必要がある Page Object はコンテキストを明示する目的に対しては 重い アプローチ
Context Enclosure 現在のコンテキストに応じてスクリプトの一部を囲う Page Objectよりも「コンテキストを明示する」という意図が明確になる cy.visit("https://demo.realworld.io/#/register"); // 新規登録ページに遷移 // この部分が
Context Enclosure cy.onRegisterPage(cy => { cy.findByPlaceholderText("Username").type("foobar") cy.findByPlaceholderText("Email").type("
[email protected]
") cy.findByPlaceholderText("Password").type("Pass1234") } ※ 名前は先日考えたのでググってもろくなのがでてきません 実装のサンプルは https://zenn.dev/tsuemura/articles/13b0ea44c1a20a
Context Enclosure の実装方法 Cypress.Commands.add("onRegisterPage", (fn) => { fn(cy); }); 1ページにつき3行で実装でき軽量
Cypressの場合はカスタムコマンドで実装する
コンテキスト内でのみ利用できるコマンド Cypress.Commands.add("onRegisterPage", (fn) => { Cypress.Command.Add("showMessage", (message) => { //
独自コマンドの定義 cy.log(message) }) cy.url().should('include', 'register') // register ページにいることを確認 fn(cy); }); onRegisterPage の中でだけ利用できる showMessage というコマンドを定義し た 例えば login や fillCredentials のようなhelperを定義してあげるとテストコ ード記述が楽になる 同時に onRegisterPage が呼ばれた段階で register を含むURLにいることを確 認している
Context Enclosure の利点 最低限の実装であれば各ページ3行ぐらいで済むので楽 全てのページに実装するのもそう大変ではない 「あるコンテキストにいる」という検証をセットで実装できる コンテキストに応じて独自のコマンドを実装できる Context Enclosure の欠点
こないだ考えたばっかりなのであんまり枯れたアイディアではないこと
今日ほとんど Context Enclosure の話をしに来たんで フィードバックもらえると助かります
まとめ
まとめ 悩まずにテストコードを読み書きするためにリーダビリティに気を使う そのためにセマンティクス(≒ アクセシビリティ)とコンテキストの2つを紹介した ユーザー目線で、文脈が明確なテストコードを書こう
Enjoy Testing! スライドか?欲しけりゃくれてやるぜ…… 探してみろ 今日の発表資料の全てをSpeakerdeckに置いてきた (Twitter / Zoomのチャットとかでも共有されると思います)