1、前提
做過(guò)一段時(shí)間UI層自動(dòng)化声离,就會(huì)深深的體會(huì)到一個(gè)痛點(diǎn):版本迭代太快,UI層元素的屬性經(jīng)常變換瘫怜,導(dǎo)致維護(hù)人員需要花大把的時(shí)間去維護(hù)代碼术徊,為了節(jié)省維護(hù)成本及時(shí)間,就可以利用PageObject 這種設(shè)計(jì)模式鲸湃,它就大大的減少了維護(hù)時(shí)間赠涮。
PageObject設(shè)計(jì)模式:是將某個(gè)頁(yè)面的所有"元素(包含控件)屬性"及"元素操作"封裝在某個(gè)特定的類(lèi)(Class)里面,目的就是測(cè)試代碼與被測(cè)頁(yè)面對(duì)象代碼分離暗挑,后期如果有頁(yè)面元素發(fā)生了更改,只需要修改相應(yīng)Page類(lèi)里面的獲取屬性的代碼笋除,測(cè)試層代碼無(wú)需修改。
2炸裆、場(chǎng)景
使用selenium實(shí)現(xiàn)自動(dòng)打開(kāi)XXXX 首頁(yè)垃它,然后輸入手機(jī)號(hào)、密碼,點(diǎn)擊登錄后退出
瀏覽器:chrome 操作系統(tǒng): OSX 10 開(kāi)發(fā)工具:IntelliJ IDEA 測(cè)試框架:TestNG
3国拇、以下以自己的一個(gè)例子作為講下洛史,如下截圖是代碼結(jié)構(gòu)
*report:存放運(yùn)行后的測(cè)試報(bào)告
*core:公共基礎(chǔ)類(lèi)
*pages:存放頁(yè)面對(duì)象
*tests:運(yùn)行測(cè)試用例
*utils:打印日志信息的一些配置格式
*resources:log4j配置以及testng 運(yùn)行配置
步驟一、首先在pom.xml 里面需要引入jar包贝奇,以下實(shí)例用到selenium-java虹菲、TestNg、Log4j
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- test -->
<groupId>webautotest</groupId>
<artifactId>webautotest</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-firefox-driver</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-chrome-driver</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/java/pages/weiDianTest.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</project>
步驟二掉瞳、編寫(xiě)公共模塊,初始化準(zhǔn)備
public class TestBase {
{
// System.setProperty("webdriver.firefox.marionette", "/Users/chenxiaoqin/Downloads/geckodriver");
System.setProperty("webdriver.chrome.driver", "/Users/chenxiaoqin/Downloads/chromedriver");
}
// protected WebDriver driver = new FirefoxDriver();//打開(kāi)火狐瀏覽器
ChromeOptions options =new ChromeOptions();
protected WebDriver driver = new ChromeDriver(options);
//獲取當(dāng)前類(lèi)的類(lèi)名傳值給logger,該句的作用就是用log4j打印日志時(shí)知道是哪個(gè)類(lèi)下面的打印輸出信息
public TestBase(){
try {
_newTest1();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
protected String getUrl() {
return "https://www.XXX.com";
}
protected Logger logger = LogManager.getLogger(getClass().getSimpleName());
/**
*
* 程序入口浪漠,打開(kāi)需要測(cè)試的url地址
* */
protected void _newTest1() throws MalformedURLException, InterruptedException {
driver.get(getUrl());//打開(kāi)需要測(cè)試頁(yè)面的url
Thread.sleep(2000);
//chrome最大化
options.addArguments("--start-maximized");
//driver.manage().window().maximize();//獲取當(dāng)前窗口最大化陕习,這個(gè)方法是不支持IE跟谷歌瀏覽器
Thread.sleep(1000);
}
@AfterMethod
protected void tearDown(){
driver.quit();
}
}
步驟三、使用PageFactory初始化pageObject對(duì)象址愿,它存在于org.openqa.selenium.support庫(kù)里面该镣,它提供的方法都是靜態(tài)的,可以直接調(diào)用响谓,提供以下4種方法:
initElements(WebDriver driver, Class<T> pageClassToProxy)
initElements(WebDriver driver, Object page)
initElements(ElementLocatorFactory factory, Object page)
initElements(FieldDecorator decorator, Object page)
一般在實(shí)際應(yīng)用中,我們可以這樣使用:
PageFactory.initElements(dr, XXX.class);
或者這樣使用:
PageFactory.initElements(new AjaxElementLocatorFactory(dr, 10) ,XXX.class);
后者加入了初始化元素時(shí)等待時(shí)間
通過(guò)initElements方法初始化的各個(gè)頁(yè)面對(duì)象损合,AjaxElementLocatorFactory方法可以查找元素時(shí)都會(huì)在指定的TIMEOUT時(shí)間內(nèi)不斷重試,如果在指定時(shí)間內(nèi)定位到元素則馬上繼續(xù)娘纷,如果指定時(shí)間內(nèi)未找到則拋出NoSuchElementException異常嫁审。具體事例如下:
package pages;
import core.TestBase;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.AjaxElementLocatorFactory;
import org.openqa.selenium.support.pagefactory.ElementLocatorFactory;
/**
* Created by jean.
*/
public class GeneralPage {
protected WebDriver driver;
public GeneralPage (WebDriver driver) {
this.driver = driver;
//通過(guò)initElements方法初始化的各個(gè)頁(yè)面對(duì)象,AjaxElementLocatorFactory方法可以查找元素時(shí)都會(huì)在指定的TIMEOUT時(shí)間內(nèi)不斷重試赖晶,如果在指定時(shí)間內(nèi)定位到元素則馬上繼續(xù)律适,如果指定時(shí)間內(nèi)未找到則拋出NoSuchElementException異常。
PageFactory.initElements(new AjaxElementLocatorFactory(driver, 3000), this);
}
/**
* 封裝sendKey文本框輸入方法
* 封裝click點(diǎn)擊事件方法
*
* */
protected void sendKeys(By by, String value) {
driver.findElement(by).sendKeys(value);
}
protected void click(By by) {
driver.findElement(by).click();
}
}
步驟四遏插、創(chuàng)建LogonPage,使用@FindBy來(lái)查找頁(yè)面元素捂贿,支持的類(lèi)型有:id
、name胳嘲、className厂僧、css、tagName了牛、linkText颜屠、partialLinkText、xpath
package pages;
import core.TestBase;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.FindBy;
import org.testng.annotations.Test;
import java.net.MalformedURLException;
/**
* @author jean
* 測(cè)試場(chǎng)景:打開(kāi)頁(yè)面輸入手機(jī)號(hào)白魂、密碼點(diǎn)擊登錄
*/
public class LogonPage extends GeneralPage{
@FindBy(id="nickName0")
private WebElement nickName;
@FindBy(id="logPsw")
private WebElement passWord;
@FindBy(css="button.ant-btn.ant-btn-primary.login-btn")
private WebElement loginButton;
public LogonPage(WebDriver driver) {
super(driver);
}
public LogonPage nameInput() throws InterruptedException {
nickName.sendKeys("XXXXXXXXXXX");
Thread.sleep(3000);
return this;
}
public LogonPage passWordInput() throws InterruptedException {
passWord.sendKeys("XXXXXXXXX");
Thread.sleep(3000);
return this;
}
public LogonPage buttonClick() throws InterruptedException {
loginButton.click();
Thread.sleep(3000);
return this;
}
}
步驟五汽纤、創(chuàng)建執(zhí)行Test類(lèi)
package tests;
import core.TestBase;
import org.testng.annotations.Test;
import pages.LogonPage;
/**
* Created by chenxiaoqin on 9/10/17.
*/
public class LoginTest extends TestBase {
@Test(priority = 0)
public void login1() {
try {
LogonPage logonPage = new LogonPage(driver)
.nameInput()
.passWordInput()
.buttonClick();
} catch (Exception e) {
e.printStackTrace();
}
logger.info("測(cè)試成功");
}
}
對(duì)于日志的打印輸出、數(shù)據(jù)的存儲(chǔ)福荸、多個(gè)用例的順序執(zhí)行蕴坪,后續(xù)將持續(xù)更新...