PageObjectパターンについてちょっと考える

概要

  • PageObjectパターンのざっくり解説
  • 考えたこと試してみたこと
  • 感想

PageObjectパターン

PageObjectパターンはデザインパターンの一つ。Seleniumを使っての自動化テストで再利用性の高いテストスクリプトを構築するのが主な目的 (別にSeleniumに限った話ではないと思うし、WrapperとかAdaptorっていう考え方かな?)

解説見るとこんな感じの説明をよく見る

  • Webページ(HTMLのコーディング)の実装詳細を隠蔽する。
  • 機能を表す言葉に変換する。
  • テストを記述しやすくする。

どうやるかってーと

  • 実装詳細の隠蔽: Seleniumを使うときに書かれるcssセレクタ―やxpath等といったhtmlの情報はPageObject内でだけ持たせる。これで外から隠す。
  • 言葉の変換: PageObjectに書かれたSeleniumを使ったコードを機能由来の名前名を付けることで機能仕様を記述する。
  • テストの記述しやすさ: PageObjectのメソッドの返却値に別のPageObjectにする。こうすることでメソッドチェーンでテストコードを記述でき見やすくなる。
考えたこと試してみたこと

「記述しやすくする」と「HTMLの詳細隠蔽・機能記述」はどうも両立させるとPageObjectが重くなり過ぎない?(単一責務の法則に違反する)とかちょっと思った。 そこで次のように一つのページを2層に分けてみることを考えてみた。

  • 詳細隠蔽用のクラス(仮にPageCoreクラスと呼ぶ)
  • Coreクラスを利用してテスト記述に求められる機能を実装する。(こっちPageFacadeクラスと呼ぶ)

PageCoreクラスはロケータとページの機能を表現するメソッドを持つ。あくまでページとそのコマンド群という位置づけのため各メソッドの返却値はvoidとした。

PageFacadeクラスはテストで利用されることを前提に高級な機能を持たせた。 例えばロードされるのを待つとかいう制御に関するコードとか。書きやすくするためのFacadeクラスには別のFacadeクラスを返すとか。

感想

当初の目的から考えるこの実装は失敗があったように感じる。何が起きたかっていうと、PageCoreクラスが画面を表現しきれていない。

画面同士は遷移元・遷移先という繋がりがあるはずなのにPageCoreクラスにそれが書かれていない。つまり画面機能の情報がPageFacade側とPageCore側で分けられちゃった。(各画面の機能ができるかはCoreクラスに書けたんだけどね)

ただ、画面の機能を2クラスに分けるという考え方自体はありかなぁとも思う。 その場合、例えば何らかのログインページ(ユーザーID入力欄、パスワード入力欄、ログインボタンを持つとする)を表現する場合 PageCoreクラスが持つメソッドは

  • public void putId(String)
  • public void putPassword(String)
  • public void pushLoginButton(String)

みたいな構成する部品の機能を由来とする名前のメソッド名を持って、 PageFacadeクラスは

  • public AfterPage login(String, String)

みたいなその画面の機能を由来として名前のメソッドを持つことになるのかな。 画面遷移図と画面機能の説明に対応するようなイメージ。

後、PageObjectパターンがPageObjectパターンを返却するってのはその画面についての機能の一部である「画面遷移先」の情報を表すためであってメソッドチェーンで書きやすくなるのはおまけ的な効果かなと思う。