5.2. LoginPage
まず、ログイン画面を表すPageObjectを下記のように作成します。
package com.example.pages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.CacheLookup; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class LoginPage { // ① private final WebDriver driver; @FindBy(name = "username") // ② @CacheLookup // ③ private WebElement username; @FindBy(name = "password") @CacheLookup private WebElement password; @FindBy(xpath = "//button[@type='submit']") @CacheLookup private WebElement loginButton; public LoginPage(WebDriver driver) { // ④ this.driver = driver; PageFactory.initElements(driver, this); } public LoginPage open(String baseUrl) { driver.get(baseUrl + "/login/index"); return this; } public LoginPage typeUsername(String key) { // ⑤ username.sendKeys(key); return this; } public LoginPage typePassword(String key) { password.sendKeys(key); return this; } public HomePage submitLoginExpectingSuccess() { // ⑥ loginButton.click(); return new HomePage(driver); } public LoginPage submitLoginExpectingFailure() { // ⑦ loginButton.click(); return new LoginPage(driver); } }
はじめに、①のとおりログイン画面を表すクラスを宣言します。特定のクラスを継承したり、インターフェースを実装する必要はありません。
ログイン画面上の要素は、②のように指定します。@FindByアノテーションには、nameやxpath属性の他に、idやcssなど、By.findElementと同程度のものを指定することができます。詳細はJavaDocを参照してください。
③は、構築したWebElementをキャッシュする指定です。このアノテーションがない場合、ログイン画面にアクセスするたびにWebElementを構築するので、パフォーマンスが落ちてしまいます。サンプルアプリケーションの画面要素は常に同じなので、このアノテーションを指定しましたが、JavaScriptでDOMを書き換えるような画面の場合は、このアノテーションを指定すると期待通りにテストが動作しないので注意してください。
④は、このPageObjectを初期化するコンストラクタです。PageFactory.initElement()を実行しないと、WebElementが初期化されず、後続の処理でNullPointerExceptionが発生してしまうので、注意してください。
ログイン画面上の機能は、⑤以降のように宣言します。ここではユーザー名を入力する機能などをメソッドとして宣言しています。どの機能をどの程度の細かさで宣言するかは、テスト次第です。あまり難しく考えずに、必要になった時点で追加していけばよいでしょう。
⑥はログインに成功した場合の振る舞いを表現するメソッドです。ログインに成功した場合はホーム画面に遷移するので、ホーム画面を表すHomePageクラスを返却します。一方、ログインに失敗した場合はログイン画面に遷移するので、⑦のようにLoginPageクラスを返却する別のメソッドとして宣言します。
5.3. HomePage
同じようにして、ホーム画面を表すPageObjectを作成します。
package com.example.pages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.CacheLookup; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class HomePage { private final WebDriver driver; @FindBy(linkText = "Logout") @CacheLookup private WebElement logoutLink; public HomePage(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); } public LoginPage logout() { logoutLink.click(); return new LoginPage(driver); } }
特に難しいところはないと思います。ログアウト用のアンカーがあり、これをクリックするとログイン画面に遷移します。
5.4. 改善したテストケース
最後に、これらのPageObjectを使って、変更後の仕様に対応するようテストケースを修正しましょう。ここでは、ユーザー名に「username」、パスワードに「password」を入力するとログインできるものとします。
// 省略 public class SampleTest { // 省略 @Before public void setUp() throws Exception { driver = new FirefoxDriver(); baseUrl = "http://se2sample2.herokuapp.com/"; driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); } @Test public void testSample() throws Exception { LoginPage loginPage = new LoginPage(driver); loginPage.open(baseUrl); loginPage.typeUsername("username"); loginPage.typePassword("badpassword"); loginPage = loginPage.submitLoginExpectingFailure(); assertEquals("Login", driver.getTitle()); loginPage.typeUsername("username"); loginPage.typePassword("password"); HomePage homePage = loginPage.submitLoginExpectingSuccess(); assertEquals("Home", driver.getTitle()); loginPage = homePage.logout(); assertEquals("Login", driver.getTitle()); } // 省略 }
仕様変更対応後のサンプルアプリケーションを参照するよう、baseUrlの値を変更してあるので注意してください。
画面仕様と強く結びついたコードが排除され、仕様変更に強いテストケースに改善されたことが分かると思います。
修正が完了したら、JUnitテストケースとして実行して、引き続きテストが成功することを確認してください。