📘

XPathとは何か? E2Eテストではどのように指定すべきか?

2024/10/20に公開

業務中にE2Eテストの自動化を担当する機会があり、
その際にロケーター指定でXPathを書く機会があったので、
XPathについてや、E2Eテストの自動化の際に備忘も兼ねてまとめておきます。

E2Eテストとは?

本題に入る前に、E2Eテストとはどのようなものかについてまとめておきます。

E2Eテストとは、End to Endテストの略で、
ブラウザやアプリを実際にUIを操作して期待通りに動くかを確かめるようなテストです。

実際にUIを操作するために人の手を介して行うか、
リグレッションテストのように繰り返し行う類のテストであれば、
自動化してプログラムを実行させるような行い方もあります。

※業務で私が自動化しているのも、リリースの度に行うリグレッションテストです。
自動化したテストを繰り返し実行し、自動化するのに投下した工数やツールの導入にかかった費用(導入していればの話ですが)を超えた時に初めて利益を生み出します。

XPathとは?

MDNを引用すると、以下の通りです。

XPath は XML Path Language の略称です。非 XML 構文を使って、柔軟な方法で XML 文書の様々な部分をアドレッシングする(指し示す)ことができます。さらに、文書中で指し示されたノードがパターンに一致するかどうかの判定を行うこともできます。

簡単に説明すると、E2Eテストを自動化する際に、確認する対象のページ要素や、
操作する対象のページ要素を指定するために使うものです。

XPathをブラウザで取得する方法

WEBページのXPathであれば、以下のような流れで、開発者ツールを使って取得することが可能です。

1.任意のWebページを開き、開発者ツールをを立ち上げる

好きなWebページを開き、macならcommand+option+iを押します。
windowsであれば、ctrl+shift+iです。

※休日に肩の力を抜いて書いているので、
Webページの選択が筆者の趣味丸出しな点についてはご容赦ください。

2.開発者ツール左上の矢印アイコンをクリック後、好きなページ要素をクリック

上記の画像のようなイメージです。
このようにすることで、開発者ツール上のクリックした要素のHTMLに自動的に移動できます。

3.開発者ツール上のHTML上で右クリック>コピー>XPathをコピー

上記の画像のようなイメージです。
結果的に、以下のようなXPathが取得できました。

/html/body/div[1]/main/section/div/div[4]/div[2]/div/ul/li[3]/a/div[1]/img

これは、htmlの階層構造を上から順に辿ったもので、
インデックス番号はプログラミング言語の配列とは異なり、
1は1番目の要素を意味します。
(0は指定しません。)

E2Eテストにおける最適なXPathの指定はどのようなものか?

残念ながら、先ほどブラウザから取得したXPathを用いてE2Eテストを作ろうとするのは適切ではないと思います。

HTMLの最も上の階層からのすべてのページ要素の構成に依存した指定の方法になっているため、
ターゲットとなる要素とは異なる箇所に少しでも変更が加わった時点で、
ターゲットとなる要素が指定できなくなるためです。
(そして、ターゲットとなる要素が取得できずに、不具合がないにも関わらずテストが失敗します。)

私が考える最適なE2Eテストにおける最適なXPathの指定(要素の指定)は、
最低限守られていればいいことを盛り込んで指定するというものです。

仮に上の画像をE2Eテストの操作のターゲットにするのであれば、
佐々木美玲さんの画像を指定できれば良い話なので、
私であれば以下のいずれかにすると思います。

近くに佐々木美玲さんの名前が表示されていれば良いと考えるのであれば、以下のようになります。

//div[text()="佐々木 美玲"]/preceding-sibling::div/img

写真をリニューアルするたびにsrc属性の指定を変える必要が生じますが、
写真の表示と実際に近くに表示されている名前の一致まで担保するのであれば、以下のような指定になります。

//div[text()="佐々木 美玲"]/preceding-sibling::div/img[@src="https://cdn.hinatazaka46.com/images/14/235/7c13d7b8915d31edbe0325581728d/800_800_102400.jpg"]

上記の指定の意味は、分解して説明すると以下のようになります。

  • "//"は途中までの階層構造の省略を表すので、最上位の"html"から書く必要がなくなる
  • "div[text()="佐々木 美玲"]"は、divタグで、"佐々木 美玲"という文字が中にあるということ
  • "/preceding-sibling::div"は、上述のdivタグの前にある兄弟要素のdivタグのこと
  • "/img"は、上述のdivタグの子要素のimgタグのこと(2つ目のXPathでは、src属性まで指定)

ちなみに、画像のhtmlの構造は以下のような感じになっています。

<li class="p-member__item" data-member="8">
    <a href="/s/official/artist/8?ima=0000">
      <div class="c-member__thumb">
        <img src="https://cdn.hinatazaka46.com/images/14/235/7c13d7b8915d31edbe0325581728d/800_800_102400.jpg" onmousedown="return false" onselectstart="return false" oncontextmenu="return false">
      </div>
      <div class="c-member__name">
        佐々木 美玲
      </div>
      <div class="c-member__kana">
        ささき みれい
      </div>
    </a>
</li>

最後に

記事内に頻繁に画像として出てきた、日向坂46のメンバー紹介ページはこちらです。

閲覧したことがある方もない方も、要チェックです!

Discussion