需求例子
比如我们使用java+Selenium编写页面自动化测试的功能。
现在有个登录页面。
1. It works
public class Login {
public void testLogin() {
// fill login data on sign-in page
driver.findElement(By.name("user_name")).sendKeys("testUser");
driver.findElement(By.name("password")).sendKeys("my supersecret password");
driver.findElement(By.name("sign-in")).click();
// verify h1 tag is "Hello userName" after login
driver.findElement(By.tagName("h1")).isDisplayed();
assertThat(driver.findElement(By.tagName("h1")).getText(), is("Hello userName"));
}
}
面向过程就是命令式的编程,就是意识流,把脑子里的想法转换成指令,让计算机去执行。
这样的模式是跳过“抽象”这一步骤,而计算机领域,“抽象”“建模”是非常重要的方法,甚至超过编码本身的重要性。
初级程序员这么写能完成任务也算达成目标了,但我们绝不能止步于此,我们要设想我们的代码要能应对更大的“变化”。
2. OOP
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
/**
* Page Object encapsulates the Sign-in page.
*/
public class SignInPage {
protected static WebDriver driver;
// <input name="user_name" type="text" value="">
private By usernameBy = By.name("user_name");
// <input name="password" type="password" value="">
private By passwordBy = By.name("password");
// <input name="sign_in" type="submit" value="SignIn">
private By signinBy = By.name("sign_in");
public SignInPage(WebDriver driver){
this.driver = driver;
}
/**
* Login as valid user
*
* @param userName
* @param password
* @return HomePage object
*/
public HomePage loginValidUser(String userName, String password) {
driver.findElement(usernameBy).sendKeys(userName);
driver.findElement(passwordBy).sendKeys(password);
driver.findElement(signinBy).click();
return new HomePage(driver);
}
}
这样就好了一点,利用OOP编程语言提供的OO特性(字段,属性,方法,继承,实现等),进行OOP开发。
中高级程序员如果能合理的划分项目的文件结构和业务对象,构建不同的抽象角色,承担不同的职责,然后在某处组装调用,那么这个项目至少不会被后来的维护者骂脏话了,也能承受相当长一段时间的业务变化,项目也能服役相当一段时间了。
然而毫不夸张的说,面试的时候夸夸其谈的所谓的大佬,也未必能很务实的去面向对象开发,尽管他们知道这些理论。他们会选择第一种方式,“又不是不能用”。要么就是眼高手低,要么就是没有热情和追求。
所以我劝大家务实一点,三思而码。梳理清楚业务需求,先抽象再建模,让代码“活”起来,你在创建一个世界,这个世界里有好多超能力的角色,它们都有自己的职责,而且尽可能地应付变化的袭击。
3. Best Practice
package pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindAll;
import org.openqa.selenium.support.FindBy;
public class Login {
final WebDriver driver;
//Constructor, as every page needs a Webdriver to find elements
public Login(WebDriver driver){
this.driver=driver;
}
//Locating the username text box
@FindAll({
@FindBy(id="wrapper"),
@FindBy(id="userName")
})
WebElement username;
//Locating the password text box
@FindBy(id="password")
WebElement pswd;
//Locating Login Button
@FindBy(id="login")
WebElement loginBtn;
//Method that performs login action using the web elements
public void LogIn_Action(String uName, String pwd){
username.sendKeys(uName);
pswd.sendKeys(pwd);
loginBtn.click();
}
}
public static void main(String[] args) {
driver = new ChromeDriver();
Login loginPg = PageFactory.initElements(driver, Login.class);
loginPg.LogIn_Action("---your username---", "---your password---");
driver.quit();
}
简单看好像与第二种方式没啥区别。事实上,纯熟OOP已经很棒了。如果在此基础上,还能站的更高,甚至站在上帝视角进行看待问题和抽象设计,那么无疑是最佳实践了。
这种方式使用Page Object Model
,将页面视为对象,抽象Factory,结合编程语言的高级特性(诸如反射、注解等),创造出使调用者使用起来会更加友好和简洁的对象模型。