WebDriverの使用を開始したばかりで、特にPageObjectsとPageFactoryを使用してベストプラクティスを学習しようとしています。
PageObjectsはWebページのさまざまな操作を公開し、WebDriverコードをテストクラスから分離する必要があることを理解しています。多くの場合、同じ操作を行うと、使用するデータに応じて異なるページに移動する可能性があります。
たとえば、この架空のログインシナリオでは、管理者の資格情報を提供するとAdminWelcomeページに移動し、顧客の資格情報を提供するとCustomerWelcomeページに移動します。
したがって、これを実装する最も簡単な方法は、異なるPageObjectsを返す2つのメソッドを公開することです。
ログインPageObject
package example;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class Login {
@FindBy(id = "username")
private WebElement username;
@FindBy(id = "password")
private WebElement password;
@FindBy(id = "submitButton")
private WebElement submitButton;
private WebDriver driver;
public Login(WebDriver driver){
this.driver = driver;
}
public AdminWelcome loginAsAdmin(String user, String pw){
username.sendKeys(user);
password.sendKeys(pw);
submitButton.click();
return PageFactory.initElements(driver, AdminWelcome.class);
}
public CustomerWelcome loginAsCustomer(String user, String pw){
username.sendKeys(user);
password.sendKeys(pw);
submitButton.click();
return PageFactory.initElements(driver, CustomerWelcome.class);
}
}
そして、テストクラスで次のことを行います。
Login loginPage = PageFactory.initElements(driver, Login.class);
AdminWelcome adminWelcome = loginPage.loginAsAdmin("admin", "admin");
また
Login loginPage = PageFactory.initElements(driver, Login.class);
CustomerWelcome customerWelcome = loginPage.loginAsCustomer("joe", "smith");
代替アプローチ
コードを複製する代わりにlogin()
、関連するPageObjectを返す単一のメソッドを公開するよりクリーンな方法があることを望んでいました。
ページの階層を作成して(またはインターフェイスを実装して)、それを戻り型として使用できるようにすることを考えましたが、不器用に感じます。私が思いついたのは次のとおりです。
public <T> T login(String user, String pw, Class<T> expectedPage){
username.sendKeys(user);
password.sendKeys(pw);
submitButton.click();
return PageFactory.initElements(driver, expectedPage);
}
つまり、テストクラスで次のことができます。
Login loginPage = PageFactory.initElements(driver, Login.class);
AdminWelcome adminWelcome =
loginPage.login("admin", "admin", AdminWelcome.class);
また
Login loginPage = PageFactory.initElements(driver, Login.class);
CustomerWelcome customerWelcome =
loginPage.login("joe", "smith", CustomerWelcome.class);
これは柔軟性があります-ExpiredPasswordページを追加でき、login()
メソッドをまったく変更する必要はありません-別のテストを追加して、適切な期限切れのクレデンシャルとExpiredPasswordページを期待されるページとして渡すだけです。
もちろん、loginAsAdmin()
とloginAsCustomer()
メソッドを非常に簡単に残して、それらの内容をジェネリックへの呼び出しに置き換えることができますlogin()
(その後、プライベートになります)。新しいページ(たとえば、ExpiredPasswordページ)には、別のメソッド(たとえばloginWithExpiredPassword()
)が必要になります。
これには、メソッド名が実際に何かを意味するという利点があり(ログインの結果が3つあることが簡単にわかります)、PageObjectのAPIは少し使いやすくなっています(「期待されるページ」が渡されない)が、WebDriverコードはまだ再利用されています。
さらなる改善...
単一のlogin()
メソッドを公開した場合は、それらのページにマーカーインターフェイスを追加することで、ログインからどのページに到達できるかをより明確にすることができます(各シナリオのメソッドを公開する場合、これはおそらく必要ありません)。
public interface LoginResult {}
public class AdminWelcome implements LoginResult {...}
public class CustomerWelcome implements LoginResult {...}
そして、ログイン方法を次のように更新します。
public <T extends LoginResult> T login(String user, String pw,
Class<T> expectedPage){
username.sendKeys(user);
password.sendKeys(pw);
submitButton.click();
return PageFactory.initElements(driver, expectedPage);
}
どちらのアプローチもうまくいくようですが、より複雑なシナリオでどのように拡張できるかはわかりません。このようなコード例は見たことがないので、ページ上のアクションがデータに応じて異なる結果をもたらす可能性がある場合、他のすべての人が何をするのだろうかと思います。
または、WebDriverコードを複製し、データ/ PageObjectsの順列ごとに多くの異なるメソッドを公開するのが一般的な方法ですか?