Appium入门自动化测试(13) —— PO(Page Object Model)模式

Appium入门自动化测试(十三)

前言

各位小伙伴们,又和大家见面了,今天我们聊一聊PO(Page Object Model)模式。PO模式是来自Selenium的一种测试分层的设计方式,可以把测试页面和页面元素分离,增加代码可重用行,能够让你的测试框架更容易维护,更方便管理。而Appium本质上还是继承Selenium的PO模式,自然而然的可以使用。可能又很多朋友了解过PO模式,这里要提一下PageFactory的概念, PageFactory 实际上是PO模式的延伸,主要是用来初始化PO模式种的页面对象。阅读此文大约需要20分钟,想要学设计测试框架的不妨深入理解一下PO模式。这里需要对用python的同学表达一下歉意,本篇内容还未内能够实现用python写。

那么如何理解PO模式呢? 让我们先从官方文档看起。官方文档如下:

http://www.seleniumhq.org/docs/06_test_design_considerations.jsp#page-object-design-pattern 

PO模式是page object model的缩写,顾名思义, 是一种设计模式,实现脚本的page和真实的网站页面Map起来,一一对应起来。这样能测试框架更容易维护。 比如一个登陆页面,使用PO模式后,会创建一个BaiduPage的class,该class会定义输入框,登陆搜索按钮的WebElenent ,而针对相应的Element实现相应的方法,输入框是用来输入的,就需要创建输入关键字的方法,这样就和真实的页面一致,所以这样的设计理念就是PO模式。 而PageFactory隶属PO模式,是用来初始化每个PO模式实现的Page Class,初始化对象库。

Page Object model 是当前比较流行的自动化设计模式.

用下面的图表示一下,更直观些:

Appium入门自动化测试(13) —— PO(Page Object Model)模式_第1张图片

 

Appium入门自动化测试(13) —— PO(Page Object Model)模式_第2张图片

如何使用PO

首先针对你的APP或Web,每一个页面都创建一个Class,把页面的元素和页面的控件一一对应起来,最好先创建一个BasePage的基类,封装一些比较常用的方法,让每个页面都继承该基类,然后对每个元素(页面控件)创建操作方法,比如输入框,要创建输入和清除以及获取该输入框内容的方法;比如是一个按钮,要创建点击该按钮和判断该按钮状态的方法。之后可以创建一个中间层,根据不同测试场景对之前的方法进行调用,比如搜索

a. 在输入框输入关键字

b. 点击搜索按钮

c. 获取搜索结果

在测试场景中可以把这一系列操作封装一个静态方法直接调用,在以后的每个case都能直接调用该方法进行测试。有朝一日百度主页有变化,无论如何关键字输入框和搜索按钮都在,这样你的所有用到搜索的用例无须修改,只需要在对应Page里面把定位方式或定位值修改一下。

如果使用PageFactory,需要在定义的Element添加@FindBy注解。也可以自己封装一套元素管理,比如把元素定位的方法写到xml中,以方便统一管理。

注:

在这里使用Web为例并非web比APP简单,而是我这里暂时没有iOS App和Android App界面一样的app。 原理一样,感兴趣可以自己研究。

首先创建BaiduPage

package main.java.com.dbyl.appiumCore.page;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.support.FindBy;

import io.appium.java_client.AppiumDriver;

import io.appium.java_client.MobileElement;

import io.appium.java_client.android.AndroidDriver;

import io.appium.java_client.ios.IOSDriver;

public class BaiduPage {

AppiumDriver driver;

@FindBy(xpath = "//input[@id='index-kw']")

MobileElement inputBox;

@FindBy(id = "index-bn")

MobileElement searchButton;

public BaiduPage(AppiumDriver driver) {

super();

this.driver = driver;

if (driver instanceof AndroidDriver) {

System.out.println("Android driver");

} else if (driver instanceof IOSDriver) {

System.out.println("IOS driver");

}

}

/**

* @author young

* @param url

*/

public void open(String url) {

if (driver instanceof AndroidDriver) {

System.out.println("Android driver");

} else if (driver instanceof IOSDriver) {

System.out.println("IOS driver");

}

driver.get(url);

}

/**

* @author young

* @param keyword

*/

public void typeInputBox(String keyword) {

inputBox.sendKeys(keyword);

}

/**

* @author young

*/

public void clickOnSearchButton() {

searchButton.submit();

}

/**

* @author young

* @param timeout

*/

public void waitForPageLoad(int timeout) {

driver.manage().timeouts().pageLoadTimeout(timeout, TimeUnit.SECONDS);

}

/**

* @author young

* @return

*/

public String getTitle() {

return driver.getTitle();

}

}

接下来就可以根据Page 中封装的方法做一下搜索这样的测试场景

创建中间层,使用Page

package main.java.com.dbyl.appiumCore.pageActions;

import java.util.concurrent.TimeUnit;

import org.junit.Assert;

import org.openqa.selenium.support.PageFactory;

import io.appium.java_client.AppiumDriver;

import io.appium.java_client.pagefactory.AppiumFieldDecorator;

import main.java.com.dbyl.appiumCore.page.BaiduPage;

public class BaiduPageAction {

private static AppiumDriver driver;

public static String url="http://www.baidu.com";

public static AppiumDriver getDriver() {

return driver;

}

public static void setDriver(AppiumDriver driver) {

BaiduPageAction.driver = driver;

}

/**

 * @author young

 * @param keyword

 */

public static void search(String keyword) {

BaiduPage baiduPage = new BaiduPage(driver);

PageFactory.initElements(new AppiumFieldDecorator(driver,60, TimeUnit.SECONDS), baiduPage);

baiduPage.open(url);

baiduPage.waitForPageLoad(60);

baiduPage.typeInputBox(keyword);

baiduPage.clickOnSearchButton();

baiduPage.waitForPageLoad(60);

Assert.assertTrue(baiduPage.getTitle().contains(keyword));

}

}

在测试用例中如何使用,直接使用上面的测试步骤即可

在测试用例中使用

package main.java.com.dbyl.appiumCore.tests

import io.appium.java_client.AppiumDriver;

import io.appium.java_client.MobileElement;

import io.appium.java_client.android.AndroidDriver;

import io.appium.java_client.ios.IOSDriver;

import io.appium.java_client.remote.AutomationName;

import io.appium.java_client.remote.MobileCapabilityType;

import main.java.com.dbyl.appiumCore.pageActions.BaiduPageAction;

import main.java.com.dbyl.appiumServer.AppiumServerUtils;

import org.openqa.selenium.remote.CapabilityType;

import org.openqa.selenium.remote.DesiredCapabilities;

import org.testng.annotations.AfterClass;

import org.testng.annotations.BeforeClass;

import org.testng.annotations.BeforeMethod;

import org.testng.annotations.Test;

import java.net.MalformedURLException;

import java.net.URL;

public class BaiduPageObjectDemo {

AppiumDriver driver;

public URL url;

boolean isAndroid = true;

@BeforeClass(alwaysRun = true)

public void startAppiumServer() {

AppiumServerUtils.getInstance().stopServer();

url = AppiumServerUtils.getInstance().startAppiumServerByDefault();

}

@BeforeMethod

public void setUpDriver() throws MalformedURLException {

DesiredCapabilities capabilities = new DesiredCapabilities();

if (isAndroid) {

capabilities.setCapability("browserName", "chrome");

capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.APPIUM);

capabilities.setCapability(CapabilityType.BROWSER_NAME, "chrome");

capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");

capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");

capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "5.1");

capabilities.setCapability("clearSystemFiles", true);

driver = new AndroidDriver(url, capabilities);

} else {

capabilities.setCapability("browserName", "safari");

capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "XCUITest");

capabilities.setCapability("platformName", "iOS");

capabilities.setCapability("platformVersion", "10.1");

capabilities.setCapability("deviceName", "iPhone SE");

driver = new IOSDriver(url, capabilities);

}

}

@Test

public void POTest() {

BaiduPageAction.setDriver(driver);

BaiduPageAction.search("Appium");

}

@AfterClass

public void afterTest() {

driver.quit();

}

}

总结

@FindBy 注解和直接使用FindElementBy是一样的,也可以使用FindBys,返回的是一个list和FindElementsBy一样。 需要注意的是,在使用PageFactory初始化Page Element的时候,传入的参数和Selenium的不太一样,第一个参数是AppiumFieldDecorator ,第二个参数是page。

小技巧, 使用driver instanceof AndroidDriver) 判断是什么设备,Android还是iOS,可以把共有部分的代码放倒一起,只需要设置不同的定位方式。

更多关于PO的内容,可以参考官方教程,点击原文


最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走

这些资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。希望对大家有所帮助…….

如果你不想再体验一次自学时找不到资料,没人解答问题,坚持几天便放弃的感受的话,可以加入下方我的qq群大家一起讨论交流,里面也有各种软件测试资料和技术交流。

你可能感兴趣的:(技术分享,软件测试,自动化测试)