zoukankan      html  css  js  c++  java
  • java版app自动化测试初始化模板

    项目目录介绍
    • 目录结构如下:
      (包含:驱动的基础配置、全局异常处理、异常截图、报告自动生成、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包中。
      image.png

    • 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测试报告,如下:

    模板流程说明
    • 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测试】获取:
    Coding测试

    记录工作中使用的CI/CD流程
  • 相关阅读:
    斐波那契数列 的两种实现方式(Java)
    单链表反转
    单链表合并
    两个有序list合并
    list去重 转载
    RemoveAll 要重写equals方法
    Java for LeetCode 138 Copy List with Random Pointer
    Java for LeetCode 137 Single Number II
    Java for LeetCode 136 Single Number
    Java for LeetCode 135 Candy
  • 原文地址:https://www.cnblogs.com/CodingTest/p/13744480.html
Copyright © 2011-2022 走看看