项目目录介绍
目录结构如下:
(包含:驱动的基础配置、全局异常处理、异常截图、报告自动生成、app常用操作方法封装、常用工具类封装)各包分层关系
basepage包负责存放app公共操作方法、AndroidDriver基础配置、testNG公共执行顺序BaseTest,对外暴露驱动等。BaseApp类包含app操作有:封装By类型的点击操作和输入框输入数据操作、切换到下一个窗口操作、上下左右滑动操作、具体坐标点击操作、直接使用adb命令的操作、前进后退刷新的操作等,其它方法可自行封住。
部分封装方法如下:
/**
* 通过元素定位拿到 Element 元素对象
*
* @param locator By 类型元素定位
* @return 定位到的元素
*/
public WebElement locateElement(AndroidDriver driver,By locator) {
try {
wait = new WebDriverWait(driver, 10);
return wait.until(ExpectedConditions.presenceOfElementLocated(locator));
}catch (NoSuchElementException | TimeoutException e) {
System.out.println("================当前页面未捕获该元素,继续执行用例==================");
}
return null;
}
/**
* 点击元素
* @param locator By 类型元素定位,做弹框或元素异常后接着往下执行
* @return 点击的元素
*/
public WebElement clickButton(AndroidDriver driver,By locator) {
try {
long time1 = DateUtils.getCurrentMillisecond();
MobileElement buttonElement = (MobileElement) locateElement(driver,locator);
wait.until(ExpectedConditions.elementToBeClickable(locator));
if (buttonElement.isEnabled()){
buttonElement.click();
log.info("该点击事件耗时时间(ms):"+(DateUtils.getCurrentMillisecond()-time1));
return buttonElement;
}
} catch (NoSuchElementException | TimeoutException e) {
System.out.println("================当前页面未捕获该元素,截图保留>>>>继续执行用例==================");
ScreenshotUtil.snapshot(driver);
}
return null;
// System.out.println("改点击事件耗时时间(ms):"+(DateUtils.getCurrentMillisecond()-time1));
}
/**
* 输入框输入数据
* @param locator By 类型元素定位
* @param content 输入的内容,支持多内容,可以键盘输入
* @return 输入框元素
*/
public WebElement sendInput(AndroidDriver driver,By locator, CharSequence... content) {
WebElement inputElement = locateElement(driver,locator);
inputElement.clear();
inputElement.sendKeys(content);
return inputElement;
}
/*=====================通过动作滑动==================================*/
/**
*向上滑动操作
*/
public void swipeToUp(AndroidDriver driver) {
int width = driver.manage().window().getSize().width;
int height = driver.manage().window().getSize().height;
TouchAction action=new TouchAction(driver).press(PointOption.point(width/2, height*3/4)).waitAction(WaitOptions.waitOptions(duration))
.moveTo(PointOption.point(width/2, height/4)).release();
action.perform();
}
/**
*向下滑动操作
*/
public void swipeToDown(AndroidDriver driver) {
int height = driver.manage().window().getSize().height;
int width = driver.manage().window().getSize().width;
TouchAction action=new TouchAction(driver).press(PointOption.point(width/2, height/4)).waitAction(WaitOptions.waitOptions(duration))
.moveTo(PointOption.point(width/2, height*3/4)).release();
action.perform();
}
/**
*向左滑动操作
*/
public void swipeToLeft(AndroidDriver driver) {
int width = driver.manage().window().getSize().width;
int height = driver.manage().window().getSize().height;
TouchAction action=new TouchAction(driver).press(PointOption.point(width*3/4, height/2)).waitAction(WaitOptions.waitOptions(duration))
.moveTo(PointOption.point(width/4,height/2)).release();
action.perform();
}
/**
*向右滑动操作
*/
public void swipeToRight(AndroidDriver driver) {
int width = driver.manage().window().getSize().width;
int height = driver.manage().window().getSize().height;
TouchAction action=new TouchAction(driver).press(PointOption.point(width / 4, height / 2)).waitAction(WaitOptions.waitOptions(duration))
.moveTo(PointOption.point(width*3/4,height/2)).release();
action.perform();
}
/*=====================通过具体坐标点击操作,appium&&adb两种方式==================================*/
/**
* 通过具体坐标点击
*/
public void taptest(AndroidDriver driver,int x, int y){
/**设置显示等待时间10s driver=baseAndroidDriver.getDriver(baseConfig)
特注:显示等待与隐式等待相对,显示等待必须在每一个需要等待的元素前面进行声明,如果在规定的时间内找到元素,则直接执行,即找到元素就执行相关操作
*/
wait = new WebDriverWait(driver,5);
//tap点击坐标,输入坐标,然后再release()释放坐标点,用perform()去执行一系列action操作
action = new TouchAction(driver).tap(PointOption.point(x,y)).release().perform();
}
/**
* 通过adb命令驱动被测设备
*/
public void adbInput(AndroidDriver driver ,String input){
try {
Process process = Runtime.getRuntime().exec(input);
wait = new WebDriverWait(driver,5);
process.destroy();
} catch (IOException e) {
e.printStackTrace();
}
}
page包(通用PO模式):分为data数据包和element元素操作包,把定位元素和输入框数据统一放到data包中,元素的操作放到element包中。其中元素的操作数据来源于data包中。
testcase包是根据业务流程编写用例步骤(后面的用例维护均在此包下)
resource包下可以放chromedriver驱动或者存放异常捕获的截图、测试报告自动生成index.html报告(由于使用springboot可以直接访问报告)另一种测试报告用的最多的是allure2,一个开源很好的报告模板allure2 的GitHub地址测试报告输出到allure-results包下。
allure2报告集成,win下需要先下载allure2的zip包GitHub官网下载地址allure2,下载zip包后需要配置下环境变量,用例执行完成后会生成allure-results文件夹,在当前文件夹下执行
allure serve allure-results
即可自动打开web测试报告,如下:
- extentreports报告样式如图(这里把项目源码路径修改了下,需要单独导下包,具体见接口自动化测试文章介绍)
模板流程说明
- 1、先在testcase包内写测试用例流程,testcase包下的类需要继承BaseTest 来获取driver驱动
eg:
public class YynCases extends BaseTest {
/**
* 测试示例用例,继承BaseTest获取driver驱动
* 操作层
*/
EnterYynElemnt enterMiniElemnt = new EnterYynElemnt();
public void getDriverCase(){
System.out.println(driver);
//点击弹框按钮
enterMiniElemnt.popupClick(driver);
}
}
- 2、创建page包下的element包中的元素操作类,即:EnterYynElemnt 类此包下的类需要继承BaseApp类来获取封装的公共操作方法。
@Slf4j
public class EnterYynElemnt extends BaseApp{
/**
* 继承BaseApp使用公共封装方法
* */
//点击弹框
public void popupClick(AndroidDriver driver) {
//使用封装By类型元素定位,且数据和元素分离
log.info("点击弹框");
clickButton( driver, PopupData.POPUP1);
}
}
- 3、创建page包下的data包的定位数据或者是输入框数据,所有的元素定位和输入数据均在此包下维护。上面参数POPUP1通过id定位,PopupData类下的POPUP1数据如下:
public class PopupData {
//升级弹框
public static final By POPUP1= By.id("com.tengyun.yyn:id/layout_confirm_cancel");
//第二个弹框
public static final By POPUP2 = By.id("com.tengyun.yyn:id/layout_activity_cancel");
- 4、其中第二步使用的是BaseApp封装的公共类方法clickButton
public WebElement clickButton(AndroidDriver driver,By locator) {
try {
long time1 = DateUtils.getCurrentMillisecond();
MobileElement buttonElement = (MobileElement) locateElement(driver,locator);
wait.until(ExpectedConditions.elementToBeClickable(locator));
if (buttonElement.isEnabled()){
buttonElement.click();
log.info("该点击事件耗时时间(ms):"+(DateUtils.getCurrentMillisecond()-time1));
return buttonElement;
}
} catch (NoSuchElementException | TimeoutException e) {
System.out.println("================当前页面未捕获该元素,截图保留>>>>继续执行用例==================");
ScreenshotUtil.snapshot(driver);
}
return null;
// System.out.println("改点击事件耗时时间(ms):"+(DateUtils.getCurrentMillisecond()-time1));
}
输入框输入数据方法也是很常用的
public WebElement sendInput(AndroidDriver driver,By locator, CharSequence... content) {
WebElement inputElement = locateElement(driver,locator);
inputElement.clear();
inputElement.sendKeys(content);
return inputElement;
}
- 5、最后可以统一把testcase包下的类放到testNG的入口中执行测试并生成报告(由于使用springboot框架没有用testNG的xml配置,而是通过封装方法进行配置)
/**
* 测试用例总入口
* */
@Test
public void runCases(){
//执行测试用例入口
BaseTestngInit baseTestngInit = new BaseTestngInit();
baseTestngInit.baseTestngInitCode();
}
testNG封装的工具类BaseTestngInit(工具类中也可以通过testng.xml初始化testng,具体看个人使用习惯)
/**
* 初始化testng
*/
public void baseTestngInitCode() {
//创建testng对象
TestNG testng = new TestNG();
//创建报告监听器对象
ExtentTestNGIReporterListener reportListener = new ExtentTestNGIReporterListener();
// TestLogListener testLogListener = new TestLogListener();
//设置需要执行的测试用例类
testng.setTestClasses(new Class[] { com.iappium.testcase.YynCases.class});
//添加监听器
testng.addListener(reportListener);
// testng.addListener(testLogListener);
//运行测试
testng.run();
}
- 更多测试技术分享、学习资源以及一些其他福利可关注公众号:【Coding测试】获取: