2023.3.9に開催された「JaSST'23 Tokyo」の資料です。 https://www.jasst.jp/symposium/jasst23tokyo/details.html#D4-1
ロケーターを学んでテスト⾃動化上級者を⽬指そうMagicPod CEO伊藤望JaSST’23 Tokyo
View Slide
About me• 伊藤 望 (Ito Nozomi)• 株式会社MagicPod CEO• ⾃動テストツール歴:約13年• Twitter:@ito_nozomi• 著書
MagicPod• Web & モバイルアプリのE2Eテスト⾃動化SasS• ノーコードで簡単にテスト作成• 柔軟性とメンテナンス性が強み(magicpod.com)
ユーザーさんのブログ記事‧発表MagicPodでE2Eテストを実装した話みてねのE2E⾃動テスト導⼊戦略アプリのテストにMagicPodを導⼊している話【インターンレポート】⾃動テストを実装したら衝撃を受けた学⽣の話Ubieのアプリ開発を⽀えるMagicPodを使った⾃動テストテスト⾃動化初⼼者がノーコードツール「MagicPod」でテスト⾃動化に挑戦してみた
Agenda1. ロケーター概要2. HTML概要3. ロケーター⽂法解説4. ロケーター実践トラブルシューティング5. ロケーターの使い分け基準6. XPath & CSSセレクター早⾒表
1. ロケーター概要2. HTML概要3. ロケーター⽂法解説4. ロケーター実践トラブルシューティング5. ロケーターの使い分け基準6. XPath & CSSセレクター早⾒表
「ロケーター」って?• UI⾃動テストツールにはロケーターの概念がある• セレクターとも⾔う• コード型ツールの場合、理解必須• ノーコード型ツールも裏で使っている- 理解すると、よりツールを使いこなせる1. ロケーター概要※ 例外もあります
1. ロケーター概要Webページの各画⾯要素(=画⾯項⽬)には、エンジニアが裏でシステムIDを付けている
1. ロケーター概要userAreapasswdAreasignInWebページの各画⾯要素(=画⾯項⽬)には、エンジニアが裏でシステムIDを付けている
1. ロケーター概要passwdAreasignInUI⾃動テストツールは、このシステムIDで操作対象を認識するテスト⼿順(=スクリプト)テキスト⼊⼒(userArea, nozomi.ito)テキスト⼊⼒(passwdArea, pass01)クリック(signIn)userArea
1. ロケーター概要??????システムIDがなかったり、あってもツールで認識できない時は?テスト⼿順テキスト⼊⼒(???, nozomi.ito)テキスト⼊⼒(???, pass01)クリック(???)???
1. ロケーター概要??????input[1] (上から1番⽬の⼊⼒エリアの意味) のような、別の指定⽅法を使うテキスト⼊⼒(input[1], nozomi.ito)テキスト⼊⼒(input[2], pass01)クリック(button[1])???テスト⼿順
「ロケーター」とはuserArea input[1] のように、テスト内で操作対象の画⾯要素を指定する部分1. ロケーター概要テキスト⼊⼒(userArea, nozomi.ito)テキスト⼊⼒(passwdArea, pass01)クリック(signIn)テキスト⼊⼒(input[1], nozomi.ito)テキスト⼊⼒(input[2], pass01)クリック(button[1])
ロケーターの⽂法の例1. ロケーター概要※ 細かい⽂法はツールによって異なる※ MagicPodはSeleniumに近い⽂法id=signIn システムIDがsignInの画⾯要素xpath=//input[1] 上から1番⽬の⼊⼒エリアxpath=//button[text()=ʻ検索’] テキストが「検索」のボタン
要素のロケーターを調べるには?1. ロケーター概要①Chrome上で要素を右クリックして「検証」
要素のロケーターを調べるには?1. ロケーター概要②システムIDを発⾒!
1. ロケーター概要• Webページの内部はHTMLで表される• ロケーターの理解にはHTMLの理解が不可⽋HTML
Webページの内部はHTML2. HTML概要placeholder="キーワード">検索
placeholder="キーワード">検索HTMLの構造2. HTML概要「開始タグ」と「終了タグ」のペアが1つの要素
placeholder="キーワード">検索HTMLの構造2. HTML概要「開始タグ」のみの要素もある
placeholder="キーワード">検索HTMLの構造2. HTML概要「タグ名」で要素の種類が分かる• input:各種⼊⼒エリア• button:ボタン
placeholder="キーワード">検索HTMLの構造2. HTML概要テキストは開始と終了タグに囲まれる
HTMLの構造2. HTML概要placeholder="キーワード">検索「属性」で要素の各種情報を指定• システムID、システム名• 初期表⽰テキスト(placeholder)• …
placeholder="キーワード">検索HTMLの構造2. HTML概要⼊れ⼦の要素は親⼦関係を表す
HTMLも分かったところで、よく使うロケーター⽂法を解説3. ロケーター⽂法解説
3. ロケーター⽂法解説よく使うロケーターその1 - idplaceholder="キーワード">検索id=searchシステムIDがsearchの要素 = id属性がsearhの要素
3. ロケーター⽂法解説よく使うロケーターその2 - nameplaceholder="キーワード">検索name=keywordシステム名がkeywordの要素 = name属性がkeywordの要素
3. ロケーター⽂法解説idとnameは何が違うのか?• プログラム上の役割が違う• どちらも要素を⼀意に特定するのに使える• 両⽅ある時はnameの⽅が変更されにくい
3. ロケーター⽂法解説よく使うロケーターその3 - XPathplaceholder="キーワード">検索xpath=//input[1]上から1番⽬の⼊⼒エリア = 上から1番⽬のinputタグの要素
3. ロケーター⽂法解説よく使うロケーターその3 - XPathplaceholder="キーワード">検索xpath=//input[@name=ʻkeyword’]name属性がkeywordのinput要素
3. ロケーター⽂法解説よく使うロケーターその3 - XPathplaceholder="キーワード">検索テキストが「検索」のbutton要素(属性ではないので@textと書けない)xpath=//button[text()=ʻ検索’]
3. ロケーター⽂法解説よく使うロケーターその3 - XPath戻る次へid属性がmainのform要素の下にある中で2番⽬のbutton要素xpath=//form[@id=ʻmain’]/button[2]
3. ロケーター⽂法解説よく使うロケーターその3 - XPath戻る次へxpath=//form[@id=ʻmain’]/span[2]/button[1]
3. ロケーター⽂法解説よく使うロケーターその4 - CSSセレクター• 表現⼒はXPathとだいたい同じ• 開発者はこちらのが好き• 詳細は今⽇は割愛
UI⾃動テストでよく⾒る「要素が⾒つからない」エラーの解決にチャレンジ!4. ロケーター実践トラブルシューティング
初級編4. ロケーター実践トラブルシューティング
4. ロケーター実践トラブルシューティング ‒ 初級編クリック(id=OKButton)昨⽇まで動いていたテスト
4. ロケーター実践トラブルシューティング ‒ 初級編「id=OKButton」の要素が⾒つかりませんエラーエラー時の画⾯いつものように実⾏クリック(id=OKButton)
4. ロケーター実践トラブルシューティング ‒ 初級編OKボタンあるやん..
4. ロケーター実践トラブルシューティング ‒ 初級編HTMLでOKButtonがあるか確認要素を右クリックして「検証」OKHTMLを確認
4. ロケーター実践トラブルシューティング ‒ 初級編OKButtonちゃんとありそうだが..OK
4. ロケーター実践トラブルシューティング ‒ 初級編OKButtonちゃんとありそうだが..OKよく⾒るとokが⼩⽂字!
4. ロケーター実践トラブルシューティング ‒ 初級編原因 エンジニアがボタンのidを変更したテスト⼿順も変更修正クリック(id=OKButton) クリック(id=okButton)
ちなみに4. ロケーター実践トラブルシューティング ‒ 初級編
クリック(id=OKButton) クリック(id=okButton)MagicPodならこのくらいは⾃動で修復します4. ロケーター実践トラブルシューティング ‒ 初級編
上級編4. ロケーター実践トラブルシューティング
4. ロケーター実践トラブルシューティング ‒ 上級編クリック(xpath=//div[@id=ʻmain’]/div[1]/div[1]/a[1])昨⽇まで動いていたテスト
4. ロケーター実践トラブルシューティング ‒ 上級編「xpath=//div[@id=ʻmain’]/div[1]/div[1]/a[1]」の要素が⾒つかりませんエラーエラー時の画⾯いつものように実⾏クリック(xpath=//div[@id=ʻmain’]/div[1]/div[1]/a[1])
4. ロケーター実践トラブルシューティング ‒ 上級編ちょっと何⾔ってるか分かんない..
4. ロケーター実践トラブルシューティング ‒ 上級編まずは何⾔ってるのか解釈テスト⾃動化ならMagicPodエラー時のHTML
4. ロケーター実践トラブルシューティング ‒ 上級編まずは何⾔ってるのか解釈テスト⾃動化ならMagicPodエラー時のHTML//div[@id=ʻmain’]
4. ロケーター実践トラブルシューティング ‒ 上級編まずは何⾔ってるのか解釈テスト⾃動化ならMagicPodエラー時のHTML//div[@id=ʻmain’]//div[@id=ʻmain’]/div[1]
4. ロケーター実践トラブルシューティング ‒ 上級編まずは何⾔ってるのか解釈テスト⾃動化ならMagicPodエラー時のHTML//div[@id=ʻmain’]//div[@id=ʻmain’]/div[1]//div[@id=ʻmain’]/div[1]/div[1]
4. ロケーター実践トラブルシューティング ‒ 上級編まずは何⾔ってるのか解釈テスト⾃動化ならMagicPodエラー時のHTML//div[@id=ʻmain’]//div[@id=ʻmain’]/div[1]//div[@id=ʻmain’]/div[1]/div[1]//div[@id=ʻmain’]/div[1]/div[1]/a[1]??
4. ロケーター実践トラブルシューティング ‒ 上級編たしかに⾒つからないが..そもそも何を操作したかったのか..
4. ロケーター実践トラブルシューティング ‒ 上級編テストを作った時のHTMLを⾒てみるMagicPodテスト作成時のHTML
4. ロケーター実践トラブルシューティング ‒ 上級編テストを作った時のHTMLを⾒てみるMagicPodテスト作成時のHTML//div[@id=ʻmain’]/div[1]/div[1]/a[1]あった!
4. ロケーター実践トラブルシューティング ‒ 上級編画⾯構成に変更がされていた模様MagicPodテスト作成時のHTMLテスト⾃動化ならMagicPodエラー時のHTML
4. ロケーター実践トラブルシューティング ‒ 上級編画⾯構成に変更がされていた模様MagicPodテスト作成時のHTMLテスト⾃動化ならMagicPodエラー時のHTMLクリックしたかったもの
4. ロケーター実践トラブルシューティング ‒ 上級編変更後の新画⾯でのロケーターは?テスト⾃動化ならMagicPodエラー時のHTML//div[@id=ʻmain’]/div[1]/div[2]/a[1]//a[text()=ʻMagicPod’]or
4. ロケーター実践トラブルシューティング ‒ 上級編原因 エンジニアが画⾯構成を変更したテスト⼿順も変更修正クリック(xpath=//div[@id=ʻmain’]/div[1]/div[1]/a[1])クリック(xpath=//div[@id=ʻmain’]/div[1]/div[2]/a[1])
ちなみに4. ロケーター実践トラブルシューティング ‒ 上級編
MagicPodならこれも⾃動で修復します4. ロケーター実践トラブルシューティング ‒ 上級編※ 修復し損ねるケースもありますクリック(xpath=//div[@id=ʻmain’]/div[1]/div[1]/a[1])クリック(xpath=//a[text()=ʻMagicPod’])
5. ロケーターの使い分け基準ロケーターはどれを使うのがいいのか?戻る次へxpath=//button[text()=ʻ戻る’]xpath=//button[1]xpath=//form[@id=ʻmain’]/button[1]全部同じ要素!
5. ロケーターの使い分け基準メンテナンス性が⾼い=画⾯の変更が⼊っても影響がない良いロケーター=
5. ロケーターの使い分け基準各種ロケーターのメンテナンス性を考えてみる
5. ロケーターの使い分け基準システムID、システム名• 開発者が変更することは少なめ• ReactJSを使った最近のサイトでは、idは無かったりランダムだったりで使いにくいこと多し…検索…
5. ロケーターの使い分け基準テキスト ‒ 良いテキスト• テストデータと関係ない画⾯表⽰テキストは、変更されることは少なめ• 多⾔語対応のテストをしたい場合は使えない…検索…
5. ロケーターの使い分け基準テキスト ‒ 悪いテキスト• テストデータのテキストをロケーターにベタ書きすると変更に弱くなる• テストケースの共通化の妨げにも…7,000円…
5. ロケーターの使い分け基準data-testid属性• テスト専⽤につけられた、要素を⼀意に識別する属性• 開発者は極⼒変更しないようにしてくれる(はず)• 無い時は開発チームに依頼してみましょう…検索…
5. ロケーターの使い分け基準class属性• 要素の⽬的‧デザインなどを表す種別• 多くの場合、要素を⼀意に識別するものではない…検索…
5. ロケーターの使い分け基準上からの順番変更に弱いので、できるだけ避けた⽅がよい…検索…xpath=//button[1]
5. ロケーターの使い分け基準要素のパス…MagicPod…xpath=//div[@id=ʻmain’]/div[1]変更に弱いので、できるだけ避けた⽅がよい
5. ロケーターの使い分け基準各テストツールは何を推奨しているか?
5. ロケーターの使い分け基準Seleniumhttps://www.selenium.dev/documentation/test_practices/encouraged/locators• idを推奨• ReactJSの無い頃のドキュメントなので、時代に合っていない気が
5. ロケーターの使い分け基準Cypresshttps://docs.cypress.io/guides/references/best-practices#Selecting-Elements• data-testid的アプローチを推奨• id、name、テキストはケースバイケース
5. ロケーターの使い分け基準Playwrighthttps://playwright.bootcss.com/python/docs/selectors#best-practices• UIがあまり変わらない場合は、テキストなどユーザーに⾒えているもの推奨• そうでなければdata-testid推奨• 多⾔語テストが少ない英語圏の発想な気が
5. ロケーターの使い分け基準個⼈的おすすめまずはdata-testid属性無理ならidかnameか良いテキスト
6. XPath & CSSセレクター早⾒表XPath CSSセレクターid属性がokのbutton要素 //button[@id=ʻok’] あまり使われませんid属性がokの要素 //*[@id=ʻok’] #okname属性がuserのinput要素 //input[@name=ʻuser’] input[name=ʻuser’]name属性がradioかつvalue属性がonのinput要素//input[@name=ʻradio’][@value=ʻon’] input[name=ʻradio’][value=ʻon’]data-testid属性がokのbutton要素 //button[@data-testid=ʻok’] button[data-testid=ʻok’]テキストがOKのbutton要素 //button[text()=ʻOK’] ⾮対応テキストがOKを含むbutton要素 //button[contains(text(),’OK’)] ⾮対応class属性logoを持つ要素 CSSセレクターの利⽤がお勧め .logoclass属性logoを持つdiv要素 CSSセレクターの利⽤がお勧め div.logoclass属性logoとmainを持つdiv要素 CSSセレクターの利⽤がお勧め div.logo.main
XPath CSSセレクター上から2番⽬のinput要素 //input[2] ⾮対応id属性がmainの要素直下のdiv要素 //*[@id=ʻmain’]/div #main > divid属性がmainの要素の下にあるdiv要素//*[@id=ʻmain’]//div #main divid属性がmainの要素の直下にあるdiv要素のうち上から2番⽬のもの//*[@id=ʻmain’]/div[2] #main > div:nth-of-type(2)id属性がmainの要素直下のdiv要素のさらに直下のinput要素//*[@id=ʻmain’]/div/input #main > div > inputid属性がokのbutton要素の親要素 //button[@id=ʻok’]/.. ⾮対応id属性がmainの要素と同階層で、それよりも後ろにあるdiv要素//*[@id=ʻmain’]/following-sibling::div #main ~ divid属性がmainの要素と同階層で、それよりも前にあるdiv要素//*[@id=ʻmain’]/preceding-sibling::div ⾮対応※ 「⾮対応」の⼀部はPlaywrightなら可能6. XPath & CSSセレクター早⾒表
今⽇お話できなかったこと• CSSセレクターの詳細• モバイルアプリ(Appium)のロケーター• 相対ロケーター(Relative Locator)• 良いロケーターが本当に無い場合
MagicPodならロケーターは⾃動計算&⾃動修復!@MagicPodJP
イベント告知
Thank you!