SeleniumのPageObjectパターンを学ぶ

SeleniumにおけるPageObjectパターンとは、ページを1つのオブジェクトとしてとらえるデザインパターンの1種のこと。

PageObjectパターンを使用してSeleniumを使ったテストスイートを構築することで、コードの重複化を防ぐことができる。

PageObjectパターンを実装するために、以下の6点に注意を払おう。

  • publicメソッドはそのページが提供するサービスを現すようにする(The public methods represent the services that the page offers)
  • ページの内部を露出させないように心がける(Try not to expose the internals of the page)
  • 一般的には、アサーションは使用しない(Generally don't make assertions)
  • メソッドはその他のPageObjectを返す(Methods return other PageObjects)
  • ページ全体を表現するする必要はない(Need not represent an entire page)
  • 同じアクションで違う結果が生じる場合は、別々のメソッドとしてモデル化しよう(Different results for the same action are modelled as different methods)

試しにGoogleのTOPページ(https://www.google.co.jp/)と検索結果ページをPageObject化してみる。

GoogleのTOPページ(GoogleSearchPage.java)

public class GoogleSearchPage {

	protected final WebDriver driver;

	@FindBy(name = "q")
	@CacheLookup
	private WebElement searchBox;

	/**
	 * コンストラクタ
	 *
	 * @param driver
	 */
	public GoogleSearchPage(WebDriver driver) {
		this.driver = driver;
	}

	/**
	 * PageFactoryを使用してWebElementをマッピングする
	 * @return
	 */
	public GoogleSearchPage initialize() {
		// googleのトップページへ
		this.driver.get("https://www.google.co.jp/");

		return PageFactory.initElements(this.driver, GoogleSearchPage.class);
	}

	/**
	 * 検索ボックスにクエリを設定する
	 * @param query
	 */
	private void setSearchBox(String query) {
		this.searchBox.clear();
		this.searchBox.sendKeys(query);
	}

	/**
	 * 画面遷移が完了するまでwait
	 */
	public void waitForPageLoad(final String currentTitle) {
		Wait<WebDriver> wait = new WebDriverWait(driver, 10);
		ExpectedCondition<Boolean> condition = new ExpectedCondition<Boolean>() {
		    public Boolean apply(WebDriver driver) {
		        return !currentTitle.equals(driver.getTitle());
		    }
		};

		wait.until(condition);
	}

	/**
	 * 検索を行う
	 * @param query
	 */
	public GoogleSearchResultPage search(String query) {
		final String currentTitle = driver.getTitle();
		this.setSearchBox(query);
		this.searchBox.submit();
		this.waitForPageLoad(currentTitle);

		return new GoogleSearchResultPage(this.driver).initialize();
	}
}

検索結果ページ(GoogleSearchResultPage.java)

public class GoogleSearchResultPage {

	protected final WebDriver driver;

	@FindBy(className = "vsc")
	@CacheLookup
	private List<WebElement> results;

	/**
	 * コンストラクタ
	 * @param driver
	 */
	public GoogleSearchResultPage(WebDriver driver) {
		this.driver = driver;

	}

	/**
	 * PageFactoryを使用してWebElementをマッピングする
	 * @return
	 */
	public GoogleSearchResultPage initialize() {
		return PageFactory.initElements(this.driver, GoogleSearchResultPage.class);
	}

	/**
	 * 検索結果のWebElementを返す
	 * @return
	 */
	public List<WebElement> getResults() {
		return this.results;
	}

	/**
	 * ページのタイトルを返す
	 * @return
	 */
	public String getPageTitle() {
		return this.driver.getTitle();
	}
}

この2つのクラスを利用して、「hoge」でググって検索結果が表示されていることをテストしてみる。

テストコード(JUnit4)

public class GoolgeTestCase {

	private WebDriver driver;

	@Before
	public void setUp() {
		this.driver = new FirefoxDriver();
	}

	@After
	public void tearDown() {
		this.driver.quit();
	}

	@Test
	public void hogeでGoogleで検索する() {
		final String query ="hoge";

		GoogleSearchPage googleSearchPage = new GoogleSearchPage(this.driver).initialize();
		GoogleSearchResultPage googleSearchResultPage = googleSearchPage.search("hoge");

		// 検索結果ページのタイトルにhogeが含まれていること
		assertThat(googleSearchResultPage.getPageTitle(), is(containsString(query)));
		// 検索結果が0以上あること
		assertThat(googleSearchResultPage.getResults().size(), is(greaterThan(0)));

	}
}

参考