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
29k
コンテキストとセマンティクスを意識してリーダブルな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
2
700
事業継続を支える自動テストの考え方
tsuemura
0
830
テスト自動化ことはじめ(202412_オープンロジ版) / Enter the testing automation (2024 Dec, for OPENLOGI)
tsuemura
0
790
E2Eテストのシナリオと抽象化の粒度の話.pdf
tsuemura
6
750
テスト自動化ことはじめ
tsuemura
3
360
ようこそ、ソフトウェアテストの世界へ!
tsuemura
1
89
リーダブルなE2Eテストコードのための3つのC
tsuemura
7
1.1k
60分で学ぶE2Eテスト(実装編)
tsuemura
0
410
全部乗せフレームワーク CodeceptJS でE2Eテストを楽にしよう
tsuemura
7
5.4k
Other Decks in Technology
See All in Technology
ElixirがHW化され、最新CPU/GPU/NWを過去のものとする数万倍、高速+超省電力化されたWeb/動画配信/AIが動く日
piacerex
0
140
AI Agentを「期待通り」に動かすために:設計アプローチの模索と現在地
kworkdev
PRO
2
440
Creating Awesome Change in SmartNews
martin_lover
1
270
Amazon S3 Tables + Amazon Athena / Apache Iceberg
okaru
0
270
Рекомендации с нуля: как мы в Lamoda превратили главную страницу в ключевую точку входа для персонализированного шоппинга. Данил Комаров, Data Scientist, Lamoda Tech
lamodatech
0
710
アジャイル脅威モデリング#1(脅威モデリングナイト#8)
masakane55
3
200
クォータ監視、AWS Organizations環境でも楽勝です✌️
iwamot
PRO
1
300
より良い開発者体験を実現するために~開発初心者が感じた生成AIの可能性~
masakiokuda
0
160
Spring Bootで実装とインフラをこれでもかと分離するための試み
shintanimoto
7
810
アセスメントで紐解く、10Xのデータマネジメントの軌跡
10xinc
1
430
SREからゼロイチプロダクト開発へ ー越境する打席の立ち方と期待への応え方ー / Product Engineering Night #8
itkq
2
640
システムとの会話から生まれる先手のDevOps
kakehashi
PRO
0
280
Featured
See All Featured
The Power of CSS Pseudo Elements
geoffreycrofte
75
5.8k
For a Future-Friendly Web
brad_frost
176
9.7k
YesSQL, Process and Tooling at Scale
rocio
172
14k
Reflections from 52 weeks, 52 projects
jeffersonlam
349
20k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
2.9k
Build The Right Thing And Hit Your Dates
maggiecrowley
35
2.6k
Typedesign – Prime Four
hannesfritz
41
2.6k
Thoughts on Productivity
jonyablonski
69
4.6k
Optimizing for Happiness
mojombo
377
70k
How to Think Like a Performance Engineer
csswizardry
23
1.5k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
GraphQLとの向き合い方2022年版
quramy
46
14k
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のチャットとかでも共有されると思います)