接 Selenium自行整理【四十七】
接下来以 126 邮箱登录为例演示 Page Object 的进一步封装。
首先创建 LoginPage.java 类。
package com.po.demo;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class LoginPage {
public static class getElement{
public static final String title = "126 网易免费邮--你的专业电子邮局";
public static final String iframe_xpath= "//*[@id='loginDiv']/iframe";// 通过 XPATH 获取页面元素
public static final String username_name = "email";
public static final String password_name = "password";
public static final String login_button_id = "dologin";
public static final String login_success_text_id = "spnUid";// 登陆成功的用户名
}
private WebDriver driver;
private String url;// 登陆页面的 URL
public LoginPage(WebDriver driver, String url) { // 声明对象时,自动加载页面
this.driver = driver;
this.url = url;
this.driver.get(this.url);// 加载页面
}
// 获取页面标题
public String getTitle() {
return this.driver.getTitle();
}
// 检测页面是否加载,判断 title 是否相等,返回 T/F
public boolean isLoaded() {
System.out.println(this.getTitle());
return LoginPage.getElement.title.equals(this.getTitle());
}
// 表单的进入
public void login_iframe() {
WebElement xf = this.driver.findElement(By.xpath(LoginPage.getElement.iframe_xpath));
this.driver.switchTo().frame(xf);
}
// 表单的退出
public void login_iframe_out() {
this.driver.switchTo().defaultContent();
}
// 登录用户名输入框
public void login_username(String username) {
WebElement element = this.driver.findElement(By.name(LoginPage.getElement.username_name));
element.clear();
element.sendKeys(username);
}
// 登录密码输入框
public void login_password(String password) {
WebElement element = this.driver.findElement(By.name(LoginPage.getElement.password_name));
element.clear();
element.sendKeys(password);
}
// 登录按钮
public void login_button() {
this.driver.findElement(By.id(LoginPage.getElement.login_button_id)).click();
}
//登陆方法,传入用户名和密码,并点击登陆按钮,然后根据 title 判断跳转是否成功
public void login(String username, String password) {
login_iframe();
login_username(username);
login_password(password);
login_button();
login_iframe_out();
}
// 返回登录成功之后的用户名
public String user() {
String text = this.driver.findElement(By.id(LoginPage.getElement.login_success_text_id)).getText();
return text;
}
}
这个例子中,Page 层的设计大概分三部分,首先,把元素的定位方法定义为常量;接下来,把对每一个元素的操作定义成一个方法;最后,再把每一个方法定义成一个操作,对外提供入口。至于浏览器的驱动,由类的构造方法来获得。
最后,创建 LoginPageTest.java 类,看一个用例层如何使用调用 Page 层的方法。
在 setUp()方法中调用 LoginPage 类,传入浏览器驱动及 URL,从而拿到 this.page 对象,接下来就可以通过 this.page 来调用 LoginPage 类所封装的方法了。
一个有分歧的地方是 page 对象是否应自身包含断言,或者仅仅提供数据给测试脚本来设置断言。在page 对象中包含断言的倡导者认为,这有助于避免在测试脚本中出现重复的断言,可以更容易地提供更好的错误信息,并且提供更接近只做不问风格的 API。不在 page 对象中包含断言的倡导者则认为,包含断言会混合访问页面数据和实现断言逻辑的职责,并且导致 page 对象过于臃肿。
赞成在 page 对象中不包含断言,虽然我们可以通过为常用的断言提供断言库的方式来消除重复,这可以提供更好的诊断,但从站在用户的角度去自动化的观点来看,判断是否登录成功是用户需要做的事情,不应该交给页面对象层来完成。
使用 Page Object 模式之后的另外一个好处就是有助于降低冗余。如果需要在 10 个用例里面都输入不同用户名密码登录,那么用 main()方法写起来将会变得非常简便。
因此,Page Object 模型的作用在一个测试人员自己写主场景测试案例时是不容易体会到的,因为你不需要和开发、业务交流案例,也不会写很多重复动作。但是,当你真正开始尝试 ATDD 或 BDD,当你开始写一些重要的异常分支流程时,当你开始为新需求频繁维护修改案例时,就会意识到 Page Object 的作用。