精华内容
下载资源
问答
  • 业务层该层主要是App的各种业务操作,比如登录,遍历tab,下单等,也就是说把app中各项业务的操作都封装在业务层。比如说登录操作,我们把它封装一个类,大致的流程是:首先是不是要找到登录入口(可能一个app有很多...

    业务层

    该层主要是App的各种业务操作,比如登录,遍历tab,下单等,也就是说把app中各项业务的操作都封装在业务层。比如说登录操作,我们把它封装一个类,登录的大致的流程是:首先是不是要找到登录入口(可能一个app有很多的入口),然后进入登录界面,输入用户名和密码,再点击登录按钮,这样一个完整的登录业务就算完成了。

    可能你问我为什么要这么做呢?在测试脚本中直接写不就可以了,为什么要把它们分离出来?其实这样做的目的是为了最大程度让测试用例维护性降低。如果以后需求发生变化,比如登陆的逻辑中增加了验证码等,这时只用改业务层中的登录类就可以了,而用例层中的测试脚本并不用改。

    这里写图片描述

    以下为登录业务的代码:
    
    package com.dji.action;
    
    import java.util.concurrent.TimeUnit;
    import com.dji.object.BasePage;
    import io.appium.java_client.AppiumDriver;
    
    /**
     * 登录action
     * @author charlie.chen
     *
     */
    
    public class Login  {
    
         private AppiumDriver<?> driver;
    
         private BasePage loginPage=null;
    
        public Login(AppiumDriver<?> driver) {
            this.driver = driver;
        }
    
    
        //通过登录按钮登录
        public void loginByButton(String userName,String pwd) throws Exception{
            new BasePage(driver,"menuPage").click("我");
            isLogined();
            new BasePage(driver,"minePageNo").click("登录");
            login(userName,pwd);
        }
    
    
        //通过DJI Store登录
        public void loginByStore(String email,String pwd) throws Exception{
            isLogined();
            new BasePage(driver,"minePageNo").click("DJI商城");
            login(email,pwd);
        }
    
    
        // 通过DJI Academy登录
        public void loginByAcademy(String email,String pwd) throws Exception{
            isLogined();
            new BasePage(driver,"minePageNo").click("DJI论坛");
            login(email,pwd);
        }
    
    
        //判断是否已登录,如果已登录就先退出登录
        public void isLogined() throws Exception{
            BasePage minePage=new BasePage(driver,"minePage");
            boolean flag=minePage.isElementDisplayed("用户图像");
            if(flag){
                minePage.swipeToUp();
                driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
                minePage.click("设置");
                loginOut();
            }
        }
    
        //登录操作
        public  void login(String userName,String pwd) throws Exception {   
            loginPage=new BasePage(driver,"loginPage");
            loginPage.type("登录输入账号框", userName);
            loginPage.type("登录输入密码框", pwd);
            loginPage.click("登录");  
            driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
        }
    
        //退出登录
        public void loginOut() throws Exception{
            BasePage settingPage=new BasePage(driver,"settingPage");
            settingPage.click("退出DJI账号");
            settingPage.click("确定");
        }
    }
    

    用例层

    该层是实际的测试脚本,也就是调用业务层中的各项业务操作,然后增加验证,判定结果是否正确。

    以下为登录用例:

    package com.dji.cases;
    
    import java.util.concurrent.TimeUnit;
    
    import org.testng.annotations.AfterClass;
    import org.testng.annotations.AfterMethod;
    import org.testng.annotations.AfterTest;
    import org.testng.annotations.BeforeClass;
    import org.testng.annotations.BeforeMethod;
    import org.testng.annotations.BeforeTest;
    import org.testng.annotations.Listeners;
    import org.testng.annotations.Parameters;
    import org.testng.annotations.Test;
    
    import static org.assertj.core.api.Java6Assertions.*;
    
    import com.dji.action.Login;
    import com.dji.object.BasePage;
    import com.dji.utils.DriverFactory;
    import com.dji.utils.TestNGListener;
    
    import io.appium.java_client.android.AndroidDriver;
    
    @Listeners({ TestNGListener.class })
    public class LoginTest {
    
        private AndroidDriver<?> ad = null;
        private Login login = null;
    
        @Parameters({ "userName", "pwd" })
        @Test(description = "通过登录按钮登录")
        public void loginByButton(String userName, String pwd) throws Exception {
    
            login.loginByButton(userName, pwd);
            ad.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            // 断言验证用户名是否正确
            //Assert.assertEquals(new BasePage(ad, "minePage").findElement("用户名").getText(), "charlie.chen");   //testNG自带的断言机制
            //采用AssertJ断言机制
            assertThat(new BasePage(ad, "minePage").findElement("用户名").getText()).isEqualTo("charlie.chen");
        }
    
        @Parameters({ "userName", "pwd" })
        @Test(description = "通过DJI Store登录")
        public void loginByStore(String userName, String pwd) throws Exception {
    
            login.loginByStore(userName, pwd);
            ad.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        }
    
        @Parameters({ "userName", "pwd" })
        @Test(description = "通过DJI论坛登录")
        public void loginByAcademy(String userName, String pwd) throws Exception {
    
            login.loginByAcademy(userName, pwd);
            ad.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        }
    
        @Parameters({ "userName", "pwd" })
        @Test(description = "通过飞行记录登录")
        public void loginByFly(String userName, String pwd) throws Exception {
    
        }
    
        // /*
        // * 通过Skypixel关注登录
        // */
        // @Test
        // public void loginByAttention() throws Exception {
        // }
        //
        // /*
        // * 通过Skypixel点赞登录
        // */
        // @Test
        // public void loginByPraise() throws Exception {
        // }
        //
        // /*
        // * 通过Skypixel收藏登录
        // */
        // @Test
        // public void loginByCollect() throws Exception {
        // }
        //
        // /*
        // * 通过Skypixel评论登录
        // */
        // @Test
        // public void loginByComment() throws Exception {
        // }
    
        @BeforeMethod
        public void beforeMethod() throws Exception {
            login = new Login(ad);
            TestNGListener.setDriver(ad);
        }
    
        @AfterMethod
        public void afterMethod() throws Exception {
    
        }
    
        @BeforeClass
        public void beforeClass() {
    
            ad = DriverFactory.createAndroidDriver("PBV0216615001449", "4723", "dji.pilot", "dji.pilot.main.activity.DJIAoaActivity"); 
            ad.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        }
    
        @AfterClass
        public void afterClass() {
            // ad.closeApp();
    
        }
    
        @BeforeTest()
        public void beforeTest() throws Exception {
        }
    
        @AfterTest
        public void afterTest() {
        }
    }
    

    testng.xml文件:

    <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
    <suite name="appiumPRO" parallel="false" preserve-order="true">
    
        <parameter name="port" value="4723" />
        <parameter name="udid" value="PBV0216615001449" />
        <parameter name="appPackage" value="dji.pilot" />
        <parameter name="appActivity" value="dji.pilot.main.activity.DJIAoaActivity" />
    
        <parameter name="userName" value="charlie.chen@dji.com" />
        <parameter name="pwd" value="1weefdsew" />
    
        <test name="LoginTest" preserve-order="true">
            <classes>
                <class name="com.dji.cases.LoginTest" >
                    <methods>
                        <include name="loginByButton" />
                        <include name="loginByStore" />
                        <exclude name="loginByAcademy" />
                        <exclude name="loginByFly" />
    
                        <exclude name="loginByAttention" />
                        <exclude name="loginByPraise" />
                        <exclude name="loginByCollect" />
                        <exclude name="loginByComment" />
                    </methods>
                </class>
            </classes>
        </test>
    
    </suite>
    
    展开全文
  • 简单说一下业务接口自动化测试

    千次阅读 2019-12-06 11:49:35
    概述 在创业公司里,项目都比较赶,测试人员也是疲于测试功能模块,基本没空去写什么自动化测试,以...注意:本文主要描述一下业务接口自动化测试的方案,至于GUI自动化测试和压力自动化测试不在本文的讨论范围内。 ...

    概述


    在创业公司里,项目都比较赶,测试人员也是疲于测试功能模块,基本没空去写什么自动化测试,以提升回归测试的效率。但一个必须承认的事实便是,依赖测试人员去做全面回归测试,保证上线质量,是不可取的,因为难度太大,成本太高。因此自动化测试还是要做一些的,具体如何着手呢,下文说一下我这边的做法。

    注意:本文主要描述一下业务接口自动化测试的方案,至于GUI自动化测试和压力自动化测试不在本文的讨论范围内。


    什么是自动化测试


    定义:把人对软件的部分测试动作转化为由机器来执行。

    自动化测试只能部分替代人工,不要指望所有业务场景都通过自动化case来验证。


    做自动化测试的动机


    最大的动机:提升回归测试的效率。

    为了让垂直拆分出去的微服务能独立发展,不耦合太多不相关的业务逻辑,一般会有一些聚合的微服务应用,用于调用多个后端微服务,汇总数据后提供给前端。在创业公司里,建议先做聚合服务的自动化自测,原因是:

    聚合层是提供给小程序/APP/H5 等用的,聚合汇总了各种后端服务,针对其做自动化测试,可以用相对低的成本,尽量多的覆盖业务case。至于针对后端的各个微服务接口做自动化的,实施起来代价比较大,有大量的代码成本和维护成本,可以后续再考虑。

    聚合服务也有很多业务接口,不可能都去写对应的自动化测试代码,建议先做主流程接口的自动化测试。比如一个电商的聚合层应用,像商详、购物车、首页、订单结算页、下单,可以先做。重要业务接口的自动化测试case,尽量做到多而全,争取全面覆盖。


    数据创建的时机和手段


    接口自动化测试中,第一个要解决的问题,就是测试数据的准备。

    数据创建的时机

    时机描述优点缺点
    即时创建执行测试用例的时候,立刻创建测试数据,用例执行完后,删除掉不会有脏数据1、会导致测试用例执行时间延长了;
    2、环境不稳定的时候,无法创建数据;
    开箱即用先提前创建好测试数据,执行测试用例的时候,直接使用,并将测试数据标记为不可用(这个实施起来难度高)。测试用例执行速度快有脏数据,因为提前创建好的数据,可能会被使用掉。

    建议使用即时创建的方案是,原因如下:

    1. 自动化case之间保证独立性和相互不影响,实在太重要了,而即时创建数据就是保证这个的重要前提,且实施起来不难,虽然开箱即用 也能做到,但是代价太大,需要有专门的测试数据构建平台,成本有些大;
    2. 环境稳定性问题,可以通过时间戳开的方式,例如:晚上跑自动化测试。
    3. 如果后续自动化case多了,即时创建的方式,会导致case执行时间长,可以通过并行执行的方式。对刚搞自动化测试的,需要执行的case的量也不大啦。

    数据创建的手段

    一般有三种:

    1. 调用后端服务api创建数据;
    2. 手写sql创建数据;
    3. 组合1和2;

    大部分情况下,使用第一种方式就行了,因为造数据的后端接口,大部分都是有的。对于少部分没有的,则手写sql创建数据。


    接口入参格式和返回值断言


    接口入参格式

    测试团队熟悉哪种就用哪种,excel或者json或者完全用代码。

    接口返回值断言

    同上,测试团队熟悉哪种就用哪种,以excel为例,期望的返回值也可以一并写在excel里,自动化case调用接口获取到业务数据后,与excel中的期望值进行断言操作即可。


    编写自动化case的语言


    测试团队熟悉哪个语言就用哪个,如果是Python那就最好了。


    执行环境


    1. 将自动化测试代码,部署到一个独立的自动化测试机器上,使用jenkin job执行自动化测试代码;
    2. 被测试的目标应用,建议重新搭建一套。

    test dashboard


    case跑完后,需要生成测试覆盖率报告和列出执行成功和失败的case

    展开全文
  • 就目前个人观察到的情况,一些负责基础性组件测试的团队,比如底层平台、SDK等,或者是负责功能通用性高的产品,比如防火墙、邮件系统等,都可以做到比较高的自动化率,而且自动化测试开发的过程通常也没有那么纠结...
  • 就目前个人观察到的情况,一些负责基础性组件测试的团队,比如底层平台、SDK等,或者是负责功能通用性高的产品,比如防火墙、邮件系统等,都可以做到比较高的自动化率,而且自动化测试开发的过程通常也没有那么纠结...
  • 自动化测试】开展自动化测试的过程

    千次阅读 热门讨论 2021-05-13 21:37:33
    文章目录1)自动化测试需求分析1.1 如何确定系统是否适合做自动化测试?周期较长:稳定系统:脚本可复用:*被测系统适合怎样的自动化测试?2)调研测试工具、测试框架2.1 框架的选择2.1.1 TestNG主要特点:TestNG的...



    如果自动化测试过程是不合理的,引入自动化测试只会给软件组织或者项目团队带来更大的混乱。我们应该建立正确的自动化测试目标,制定有效的测试策略,有计划、有步骤地实施合理的测试过程,这样才能确保自动化测试获得所期望的效益。

    1)自动化测试需求分析

    当接受一个新的项目时,必须针对测试项目的具体情况进行具体可行性分析,确定一个软件系统测试中哪些范围、哪些任务是适合自动化测试的而哪些是不适合的。如果对不适合的测试任务实施自动化工作,不仅耗费过多的人力,而且效果也不一定好。

    1.1 如何确定系统是否适合做自动化测试?

    • 周期较长:

      如果被测项目是在今后一年或者几年间要不断进行开发维护的,那么就需要重复的进行大量的回归测试,这种情况下如果有自动化的回归测试体系就可以节省成本投入。
    • 稳定系统:

      已上线运行的稳定系统,开发过程中需求变动较少
    • 脚本可复用:

      脚本可复用以降低维护成本。

    • *被测系统适合怎样的自动化测试?

      自动化测试覆盖的范围很广:单元测试、集成测试、接口测试,GUI测试等等都可以实现自动化执行。
      • 不同的系统情况是不一样,有的适合或是可以做GUI的自动化测试,有的可能只适合做接口的自动化测试,所以需要针对不同的被测项目,考虑具体在哪一个环节作自动化测试
        • 比如说针对搜索引擎,前端往往比较简单,只是一个文本框和提交按钮,大部分的逻辑处理都是在后端完成的,这种情况做自动化的接口测试就可以达到事半功倍的效果。
        • 如果是被测系统有很多的页面操作,那么可以考虑GUI的自动化测试。
        • 以上这两种情况都不是绝对的,如果测试资源足够,那么在各个环节都是可以开展自动化测试的。
      • 还有一点需要考虑的是自动化测试的可行性,比如说对一个系统而言,做GUI测试是最合适的,也是最有效,但是有可能通过各种工具或者是脚本很难实现GUI的自动化测试,那么就需要考虑变通,考虑是否可以将自动化测试调整到接口测试或是集成测试等环节

    2)调研测试工具、测试框架

    2.1 框架的选择

    时下比较主流的自动化测试框架,有TestNG、unittest、pytest、Robot Framework。第一个框架基于Java,后三者基于Python,Java和Python是编写自动化测试脚本最常用的两种语言。下面就简单介绍这四款框架。

    2.1.1 TestNG

    Test NG是一款基于Java的自动化测试框架。

    说到TestNG就不得不提到JUnit,两者都是基于Java的测试框架,功能差异不大,但是TestNG底层调用的是JUnit,因此TestNG的使用对于测试人员来说更友好。而JUnit更偏向白盒测试,所以开发人员用来做单元测试比较多,而且测试结果可读性对测试人员也有一定难度。

    • TestNG使用更便捷,例如并发测试JUnit需要调用第三方库,TestNG则不需要。
    • 一般TestNG主要是测试人员使用。
    • 主要特点:

      • 涵盖单元测试、功能测试、集成测试等
      • 基于Annotation(注解)机制,测试方法更灵活:
        • 当我们想执行一部分测试脚本的时候,就可以使用xml配置文件进行配置,在xml配置文件里,可以选择某些需要执行的测试脚本,排除不需要运行的测试脚本。
      • 支持多线程测试
      • TestNG还可以自动生成html、xml格式的测试报告
        • 测试报告位于 “test-output” 目录下,只需要执行测试用例时使用TestNG执行即可自动生成,无需配置,使用便捷。

        • 还可以对报告内容的详细程度进行设置:

          • 可以说是比较完善的测试报告了,测试报告的样式如下图所示,展示比较直观、简明,可以直接看到共执行了多少个用例,成功/失败分别是多少个,设置级别更高的报告,还可以查看具体的失败情况。

          在这里插入图片描述

    • TestNG的使用方法:

      • 将测试用例生成测试套件,通过执行测试套件来执行测试用例。
      • 常用的组件如下图所示:
        在这里插入图片描述
        • @Test表示一个测试用例。
        • @BeforeMethod/@AfterMethod表示在每一个方法执行前/后执行一次。
        • @BeforeTest/@AfterMethos表示在每个测试用例执行前/后执行一次。

    例如,在使用TestNG框架时,就可以将“启动浏览器”的操作步骤封装在@BeforeTest中,“关闭浏览器进程”的操作封装在@AfterTest中,这样就提高了代码复用性

    2.1.2 unittest

    unittest是一款常用的单元测试框架。它更偏向底层,二次开发方便,因此对于测试人员来说,就具备一定的难度了。

    它的优势是Python自带框架,可生成HTML测试报告,使用的是HTMLTestRunnerNew库。由此,若基于Python开发的测试代码,就非常适合采用unittest测试框架。只需要使用自带的方法生成测试套件,执行测试套件,即可完成多种组合方式的测试。因此,针对Python的自动化测试,unittest可谓是最佳拍档,可以轻松完成大部分的测试功能。

    • unittest也可以将浏览器启动、关闭等通用方法封装,生成测试用例,再将测试用例生成测试套件来执行,如下图所示:
      在这里插入图片描述
      在这里插入图片描述

    • unittest也可以自动生成测试报告,报告形式如下图所示:

      在这里插入图片描述

      • 报告的内容与TestNG生成的报告内容相似,展势执行用例的数量、结果等信息,也可以设置详细等级、标题等信息。

    2.1.3 pytest

    pytest是基于unittest扩展的第三方测试框架,比unittest更简洁高效。

    • pytest可以执行unittest风格的测试用例,无须修改unittest用例的任何代码,有较好的兼容性。
    • pytest插件丰富,比如returnfailures插件,可用于用例出错重跑。
    • 还有xdist插件,可用于设备并行执行测试用例。
    • 可使用pytest-HTML插件生成测试报告。
    • pytest也可用来进行验收测试,适合复杂度不是很高的系统

    2.1.4 Robot Framework

    Robot Framework也是一款功能强大的自动化测试框架,基于Python的关键字驱动测试框架,自带报告生成,功能完善。因此它易用性更高,测试人员使用成本低,但灵活性就偏低了。一般多用于验收测试和验收测试驱动开发的自动化测试框架。支持跨平台(Windows/Linux/MacOS)。

    • 特点:

      • 关键字驱动测试(KDT),简化自动化过程,对测试人员来说更易读,测试数据语法也简单易用,扩展性高。
      • 例如支持Selenium第三方类库可进行Web UI自动化测试,支持Selenium Grid执行并发测试,并且可生成html测试报告但操作较麻烦。
      • 表格式的测试数据语法和关键词驱动测试使得易用性较高。

    2.1.5 框架对比

    TestNG是基于Java的测试框架,unittest、pytest、Robot Framework是基于Python的测试框架。其实测试框架的选择,更主要还是根据系统的特性,选择适合的框架

    对于unittest、pytest、Robot Framework这三个测试框架,都可支持跨平台,语言单一支持Python,差别并不大,主要如下表所示:

    在这里插入图片描述

    实际选用,可结合系统、框架的优势对号入座,以带来更高的自动化测试开发效率。

    2.2 工具的选择

    不同的测试任务会选用不同的测试工具,如单元测试须要选用单元测试工具,性能测试须要选用性能测试工具。

    • 要考虑被测系统是C/S、还是B/S结构的
    • 服务端和客户端都是用何种语言编写的
    • 数据库的类型
    • 服务器类型等等

    在选择测试工具时,要清楚测试目标和需求,确定适用的技术环境及自动工具可支持的各种测试,分析测试工具与被测软件系统的互操作性和兼容性,考虑工具的易用性、工具学习曲线或培训成本,特别是要考虑工具本身所要求的测试脚本,是否支持数据驱动、关键字驱动,以及是否容易编写、调试和维护等。

    2.2.1 UFT(QTP)

    UFT 就是以前最常用的自动化测试工具QTP,用来进行Web UI自动化测试的。QTP实现的是独占屏幕操作,仿真实际用户操作,一般用于回归测试和新版本测试

    • 特点:

      • 支持Windows平台
      • 使用VBScript编写测试脚本
      • 相比Java/C#这类语言,显然更受测试人员欢迎。

    • 测试流程:

      1、制定测试计划
      2、创建测试脚本
      3、增强测试脚本
      4、运行测试
      5、分析测试结果

    QTP的脚本生成是通过轨迹录制,再进行增强优化,最后实现回放。因此VBScript脚本的逻辑比较松散,因此对于复杂页面情况的处理能力比较弱,脚本维护的成本就非常高。最重要的是,QTP是收费的,QTP11.5版本发布改名为UFT。

    2.2.2 Selenium

    Selenium是目前最常用的一种Web自动化测试工具,是开源的,它可并行测试,模拟用户操作,贴近用户实际操作,测试效果直观

    • 它的优势:

      • 兼容性好:兼容多平台,多浏览器,多语言编写脚本,因此它从测试脚本开发,到部署运行,都比较稳定。
      • API丰富:可以实现对浏览器、页面元素、鼠标键盘、JS窗口等几乎所有的用户操作,执行效率较高。

    • 它的组成:

      当前Selenium已发展到第3代,包含三大组件,Selenium IDE + WebDriver + Selenium Grid:

      • Selenium IDE:
        Selenium IDE是Firefox中的一个组件,可以录制操作轨迹,自动生成脚本并进行回放,但它的缺点是不稳定,生成的代码效率低,定位大多采用自动的xpath方式定位,定位繁琐,回放成功率低,且不适用于复杂系统。
      • Selenium Grid:
        用于实现分布式测试。
      • WebDriver:
        是Selenium核心组件,它就是实现页面操作的组件,利用浏览器原生的API,封装成一套更加面向对象的SeleniumWebDriverAPI,直接操作浏览器页面里的元素,执行效率更高,且稳定性依赖于浏览器厂商,显然更加稳定,因此各大常见浏览器都有对应的WebDriver。
        • 例如Chrome对应chromedriver。
        • Firefox对应geckodriver。
        • IE对应iedriver。
        • 甚至比较高版本的selenium还自带了部分常用浏览器的驱动,使用起来非常方便。它的优势显而易见,使用浏览器源厂的驱动来进行自动化控制,给我们带了更高的安全感

    2.2.3 Appium

    Appium是目前最常用的一款移动端自动化测试工具,是开源的,它支持Android和iOS平台的原生应用、web应用和Hybrid应用。它的优势,支持跨平台,多语言脚本编写。因此,兼容性很好,开发便捷。

    • Appium是C/S架构,提供了基于Selenium WebDriver协议的统一接口。

    那么这里就需要说明一下Appium与Selenium的关系了。

    • Appium封装了标准的Selenium客户端类库,Appium继承了Selenium中的WebDriver,因此也是通过WebDriver实现界面的定位及操作。而Appium实现的是PC端连接移动端的桥梁作用,这样才能通过PC端对移动端进行自动化测试

    2.2.4 工具的对比

    由于Selenium和Appium都是使用的WebDriver实现操作的,因此这里只对比UFT和Selenium。

    下面这个表格,充分体现了两者之间的优势与劣势,测试人员可以根据需要选择合适的测试工具,以实现最高的测试效率:

    在这里插入图片描述

    3)搭建自动化测试框架并实施

    由leader组织搭建自动化测试框架,并且在项目中逐步地实施,发现框架的问题并改善。

    3.1 确定开展自动化需要的资源

    确定了使用何种测试工具、测试框架,就需要确定需要的资源,如:

    • 需要几个自动化测试工程师
    • 需要购买的测试工具
    • 测试机(服务器、客户机)
    • 开发自动化框架所需要的时间

    确定了需要哪些资源,就要看当前可用的资源有哪些,如果资源不足应提前申请,如招聘测试人员、购买配置测试机。甚至需要测试人员提前学习新的技术。

    3.2 开发自动化测试脚本

    自动化测试脚本的编写,必须要遵守编码规范,包括脚本的层次、命名等。将(测试)数据层、(系统)操作层和(业务)逻辑层分开,不仅构造结构化的脚本,而且构造程序对象映射、建立对象库和关键字函数库等,全面支持测试数据驱动、关键字驱动的脚本,有利于脚本的开发和维护。

    • 测试脚本的开发,和软件产品本身的开发还有许多相似之处,例如:
      • 自动化测试代码需要跟踪和维护,因此,要采用源代码管理。
      • 测试自动化也会出现缺陷,因此,需要有计划地跟踪缺陷,并且对修改后的缺陷进行验证
      • 用户需要知道如何使用工具和脚本,因此要提供用户使用手册
    • 在脚本开发中增加冗余设计,即使降低一定的性能,也要保证测试执行的稳定性。

    脚本写完了,并不代表脚本开发工作已结束,还须要调试。只有脚本运行稳定,执行的测试结果符合测试要求,才能说明测试脚本开发工作告一段落。

    3.3 测试结果分析

    自动化测试结果一般被分为3种情况——通过(pass)、失败(failed)和不确定/没有被执行TBD/unexecuted)。

    针对测试自动化执行结果,主要集中分析那些没有通过(failed)的结果

    • 分析是不是软件产品本身存在缺陷导致测试执行失败?
    • 是不是之前某个测试执行失败而导致其他大量的测试执行没通过?
    • 查看测试环境是否异常。
    • 如果产品和测试环境都没有问题,就要检查自动化测试脚本,是不是测试脚本误报信息?还是脚本的验证点设置不对?

    有时候,测试执行全部通过,也可能存在问题——脚本的验证点不够或太粗,从而错过许多验证点。

    为了更好地进行测试结果分析:

    • 一方面,尽量记录下测试过程中的重要信息,即存储好的测试执行日志(log)
    • 另一方面,提供规范的测试结果报告格式,使结果一目了然,并在失败的用例提供链接,点击链接,就能直接查看相应的测试用例和执行的log。

    4)总结自动化测试的实施过程

    自动化过程可以从3个角度描述其组成:
    在这里插入图片描述

    • 可以看作一个项目:

      自动化测试的过程就是一个项目的实施过程,经过计划、执行、评估与总结而不断提高的过程。
    • 看作软件开发的过程:

      经过测试需求的分析、自动化测试框架的设计、测试脚本的开发和验证、测试脚本的运行等流程。
      • 而且测试脚本的管理和源代码的管理也是一样的,须要通过CVS、SubVersion等工具进行配置管理,包括版本分支和合并、变更控制等。
    • 依然是一个测试过程:

      从测试需求出发,设计和执行测试用例、报告缺陷,并自动生成测试报告。


    【部分内容参考自】

    • 如何开展自动化测试:http://www.51testing.com/html/98/15165698-3716219.html
    • 自动化测试的实施:https://www.jianshu.com/p/102136c1d7a1
    • 常见自动化测试工具及框架的选用:https://www.cnblogs.com/ustcinfo-qc/p/12124174.html
    展开全文
  • 引言本章主要介绍自动化测试框架–对象库。该是UI自动化中比较关键的一,设计自动化框架,不可避免的就是对象库,有一个好的对象库,可以让整个测试框架可维护性更高,大大增强了代码的复用性。讲之前先和大家...

    引言

    本章主要介绍自动化测试框架–对象库层。该层是UI自动化中比较关键的一层,设计自动化框架,不可避免的就是对象库,有一个好的对象库,可以让整个测试框架可维护性更高,大大增强了代码的复用性。

    讲之前先和大家普及个一概念:PO模式

    PO模式

    那什么叫PO模式,为什么要用PO模式?引用如下一段话,你就会恍然大悟~

    PO模式,全称Page Object模式,是Selenium中的一种测试设计模式,主要是将每一个页面设计为一个Class,其中包含页面中需要测试的元素(按钮,输入框,标题 等),这样在写测试脚本时,可以通过调用页面类来获取页面元素。当页面某个元素id或者位置变化时,这时不用更改测试脚本,只用改下对应的页面类就行了。

    上面这段话,总结一下就是:PO就是一个设计模式,将代码以页面为单位进行组织,针对这个页面上的所有信息,相关操作都放到一个类中;从而使具体的测试用例变成了简单的调用和验证操作。

    如果你深刻理解了就应该知道了PO对象的好处,当然这只是阐述啦它的可维护性,但它的复用性就更好理解,这里就不多做解释。

    对象库的引入

    对于上面讲的PO模式,大家会不会有一个疑惑?这样一来一个app有很多page,以DJI GO为例50个左右肯定是有的吧,那这样是不是要设计50个页面类,然后每个页面类中写对应的元素。这样一来单单页面类就写这么多,感觉工程量太大,而且代码的复用性不高。

    那有没有什么改进的办法呢?

    1.首先定义一个BasePage类,毕竟所有的页面都有共同的东西,每个页面都有元素,每个页面元素都有相应的方法。该类包括一个成员变量 pageName,和封装的的方法。重写它的构造方法,用来初始化成员变量。以后每次调用某个页面时,只用new一个BasePage对象,传入对应的参数pageName,就获得对应页面。

    这里写图片描述

    package com.dji.object;
    
    import java.io.IOException;
    import java.util.HashMap;
    
    import com.dji.utils.AppiumExecutorImpl;
    import com.dji.utils.Log;
    import com.dji.utils.XmlUtils;
    
    
    import io.appium.java_client.AppiumDriver;
    import io.appium.java_client.MobileElement;
    
    
    /**
     * 封装一个BasePage的类,毕竟所有的页面都有共同的东西,每个页面都有元素,每个页面元素都有相应的方法
     * 
     * @author Charlie.chen
     *
     */
    
    public class BasePage extends AppiumExecutorImpl {
    
        protected AppiumDriver<?> driver;
        protected String pageName;  //页面名称
        protected String xmlPath;   //页面元素路径
        protected HashMap<String, Locator> locatorMap;
        public Log log = new Log(this.getClass());
    
    
        public BasePage(AppiumDriver<?> driver,String pageName) throws Exception  {
            super(driver);
            this.driver = driver;
            this.pageName=pageName;
    
            //获取资源文件page.xml的路径
            //xmlPath=System.getProperty("user.dir")+"\\src\\main\\java\\com\\dji\\pageObject\\Page.xml";   
            xmlPath=BasePage.class.getClassLoader().getResource("page.xml").getPath();
    
            //locatorMap = XmlUtils.readXMLDocument(xmlPath, this.getClass().getSimpleName());
            locatorMap = XmlUtils.readXMLDocument(xmlPath, pageName);
    
        }
    
    
    
        public void type(String locatorName, String values) {
            super.type(getLocator(locatorName), values);
            log.info("type value is:  " + values);
        }
    
    
        public void click(String locatorName) {
            super.click(getLocator(locatorName));
            log.info("click: "+locatorName);
        }
    
    
        public String getText(String locatorName) {
            // TODO Auto-generated method stub
            return super.getText(getLocator(locatorName));
        }
    
    
        public MobileElement findElement(String locatorName) {
            // TODO Auto-generated method stub
            return super.findElement(getLocator(locatorName));
        }
    
        public boolean isElementDisplayed(String locatorName) {
            // TODO Auto-generated method stub
            return super.isElementDisplayed(getLocator(locatorName));
        }
    
    
    
        /**
         * 根据locatorName获取Locator
         * 
         * @author Charlie.chen
         * @param locatorName
         * @return
         * @throws IOException
         */
        public  Locator getLocator(String locatorName) {
    
            Locator locator =  null;
    
            if(locatorMap!=null)
            {
                locator = locatorMap.get(locatorName);
            }
            return locator;
        }
    
    }
    

    上述代码中有个一个集合locatorMap,主要存储的对应的pageName和Locator内容

    2.接下来封装元素,每个元素都有相应的定位地址(xpath路径或css或id),等待时间,定位方式

    package com.dji.object;
    
    /**
     * 封装页面元素,每个元素都有相应的定位地址(xpath路径或css或id),等待时间,定位方式
     * 
     * @author Charlie.chen
     *
     */
    
    public class Locator {
    
        private String address;  //定位地址
        private int waitSec;    //等待时间
        private ByType byType;  //定位方式
    
    
        /**
         * 定位类型枚举
         * @author Charlie.chen
         *
         */
         public enum ByType{
                by, xpath, linkText, id, name, className
            }
    
    
        public Locator() {}
    
        /**
         * Locator构造器,默认定位类型By.xpath
         * 
         * @author Charlie.chen
         * @param element
         */
        public Locator(String address) {
            this.address = address;
            this.waitSec = 3;
            this.byType = ByType.xpath;
        }
    
        public Locator(String address, int waitSec) {
            this.waitSec = waitSec;
            this.address = address;
            this.byType = ByType.xpath;
        }
    
        public Locator(String address, int waitSec, ByType byType) {
            this.waitSec = waitSec;
            this.address = address;
            this.byType = byType;
        }
    
        public String getAddress() {
            return address;
        }
    
        public int getWaitSec() {
            return waitSec;
        }
    
        public ByType getBy() {
            return byType;
        }
    
        public void setBy(ByType byType) {
            this.byType = byType;
        }
    
        public ByType getByType() {
            return byType;
        }
    
    
    }
    

    对象库的管理

    针对上面的两个类BasePage和Locator,其实就是分别代表页面对象库和元素对象库。关于对象库的管理,就是将对象库中的数据,类似pageName和元素属性id,xpth等分离出来保存在page.xml文件中,这样做到了数据隔离的效果,维护性更高。

    page.xml如下

    <?xml version="1.0" encoding="UTF-8"?>
    
    <map>
        <!--locator of page map info -->
    
        <page pageName="menuPage">
            <!--Locator lists -->
            <locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'设备')]">设备</locator>
            <locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'编辑器')]">编辑器</locator>
            <locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'天空之城')]">天空之城</locator>
            <locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'我')]"></locator>
        </page
    
        <page pageName="minePage">
            <!--Locator lists -->
            <locator type="id" timeOut="3" value="dji.pilot:id/icon_user">用户图像</locator>
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_user_name">用户名</locator>
            <locator type="id" timeOut="3" value="dji.pilot:id/v2_mine_store">DJI商城</locator>
            <locator type="id" timeOut="3" value="dji.pilot:id/v2_mine_academy">DJI论坛</locator>
            <locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'礼品卡')]">礼品卡</locator>
            <locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'上传队列')]">上传列表</locator>
            <locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'消息')]">消息</locator>
            <locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'我的收藏')]">我的收藏</locator>
            <locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'更多')]">更多</locator>
            <locator type="xpth" timeOut="3" value="//android.widget.TextView[contains(@text,'设置')]">设置</locator>                       
        </page>
    
    
        <page pageName="loginPage">
            <!--Locator lists -->
            <locator type="id" timeOut="3" value="dji.pilot:id/edt_email">登录输入账号框</locator>
            <locator type="id" timeOut="3" value="dji.pilot:id/edt_password">登录输入密码框</locator>
            <locator type="id" timeOut="3" value="dji.pilot:id/btn_sign_ok">登录</locator>
        </page>
    
    
        <page pageName="settingPage">
            <!--Locator lists -->
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_back_button">返回</locator>
    
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_cellular_switch">使用手机流量上传文件</locator>
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_develop_switch">开启USB调试</locator>
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_reset_guide_button">重置新手指引</locator>
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_clean_cache_button">清除数据缓存</locator>                   
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_language_change">多语言</locator>
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_privacy_button">隐私设置</locator>
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_rate_app_button">给我们评分</locator>           
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_settings_sign_out_button">退出DJI账号</locator>
    
            <locator type="id" timeOut="3" value="android:id/button2">取消</locator>
            <locator type="id" timeOut="3" value="android:id/button1">确定</locator>
    
            <locator type="id" timeOut="3" value="dji.pilot:id/mine_user_protocol">DJIGO用户协议</locator>              
        </page>
    
    </map>
    

    分析一下page.xml中登录页,对应的pageName=“loginPage”,对应的元素名有“登录输入账号框”,“登录输入密码框”,“登录按钮”和对应的定位方式和等待时间。这样是不是一目了然,以后如果页面元素属性发生变化,只用改下以上配置文件即可。关于xml文件的读取,在第三章中有讲过,通过XmlUtils进行读取,将读取的信息保存在HashMap集合locatorMap中。

    总结

    总结一句话:就是将页面和元素封装在两个类中,然后将对应的数据抽离出来放在xml文件中管理。
    对象库大大提高了测试框架的复用性和可维护性,在测试框架中起到核心作用,这里只是我的处理方式,相信还有更简洁更易度的方法,等待大家去挖掘。

    下一章主要讲解 自动化测试框架(五):业务层和用例层,敬请期待!!

    展开全文
  • 1、为什么要使用自动化框架?...  脚本层(业务组件开发),业务层(流程的开发和组织),数据层相分离,是本次框架组织总的方针,为开展功能自动化测试提供一个高效、稳定、容易的测试实现。  3.qtp工具的
  • 大家好,本系列教程主要介绍基于Appium的UI自动化测试框架的设计和实践。我将平时的学习和工作的实践一一的总结下来,给初学者一点灵感和启发,如有不对的地方还请大家指出。 所谓UI自动化,顾名思义,主要是...
  • 自动化测试自动化测试框架与工具

    千次阅读 多人点赞 2021-05-06 21:01:01
    1.2.2 框架的基本组件1、需要配置文件管理:2、业务逻辑代码和测试脚本分离3、报告和日志文件输出4、自定义的库的封装5、管理、执行脚本方式6、第三方插件引入7、持续集成总结1.3 为什么需要自动化测试框架?...
  • 在这个分层结构中,测试自动化代码会被分成三:(1)测试用例,表达应用程序的测试逻辑。(2)领域,用业务领域术语来给待测系统建模,封装HTTP请求、浏览器控制、结果解析逻辑等,给测试用例提供一个接口。(3)...
  • 自动化测试框架

    千次阅读 2018-05-09 15:00:15
    什么是自动化测试框架 自动化测试框架是应用于自动化测试的程序框架,它提供了可重用的自动化测试模块,提供最基础的自动化测试功能,或提供自动化测试执行和管理功能的架构模块。它是由一个或多个自动化测试基础...
  • 什么是以及为什么要分层自动化测试?   最近两年我连续在ChinaTest上面开了一门叫“分层自动化测试”的课程,这几天在微博上引起了什么是以及为什么要分层自动化测试的讨论,今天闲来无事就写一篇小文来澄清一下...
  • 自动化测试介绍 自动化测试(Automated Testing),是指把以人为驱动的测试行为转化为机器执行的过程。实际上自动化测试往往通过一些测试工具或框架,编写自动化测试用例,来模拟手工测试过程。比如说,在项目迭代...
  • 前面将基础打好了,接下来就是具体的使用了,业务层主要是页面中的各种业务操作,如登录,修改用户信息等,我们把这些操作都封装在业务类中,如登录操作,我们把它封装成一个类,登录的大致流程为打开登录页,输入...
  • 自动化测试面试

    万次阅读 多人点赞 2016-03-04 09:04:38
    目前市场上 自动化测试职位开放了很多很多 几乎每个公司都会这样发布招聘信息,但是我们理解的自动化测试,是不是用人单位理解的自动化测试呢。好似与雷军理解的黑科技一样。 我们在招聘自动化测试职位的时候,又...
  • 这一篇跟大家一块探讨下自动化测试的分层理论。当下自动化覆盖了很多场景的测试,比如单元测试、接口测试、UI测试、性能测试等等,那么什么条件下更适合用自动化测试呢?先来看看经典的自动化测试分层理论吧。 自动...
  • 接口自动化测试之接口测试基础

    万次阅读 多人点赞 2020-02-11 13:29:38
    文章目录一、分层的自动化测试1.传统自动化测试2.测试金字塔3.分层自动化测试二、接口测试基础知识1.接口的含义2.接口的分类3.接口测试3.1 接口测试的含义3.2 接口测试的意义3.2.1 为什么测试接口3.2.2 接口测试的...
  • 做功能自动化测试都会不约而同的遇到一...它可以轻易实现目前比较流行的三层测试架构:脚本层,业务层,数据层相分离,为开展功能自动化测试提供一个高效、稳定、容易的测试实现。一.概述1.1业务组件(BussinessProc
  • 关键字驱动自动化测试

    千次阅读 2018-08-17 11:37:33
    为 了提高测试效率和准确性,越来越多的测试工作引入了自动化测试的思想和方法,随着自动化测试工具的发展,自动化测试更加容易实现更高效。实践证明,软件自 动化测试技术帮助软件开发和测试人员在更短的时间内开发...
  • 如何做自动化测试

    万次阅读 2016-05-26 09:58:25
    会使用自动化测试工具的测试人员不能够称之为完全的自动化测试人员,这类测试人员被称为『工具小子』(Script Kid)。这个阶段还是处于自动化测试的一个比较低级的阶段,因为这些工具都不是测试人员开发的。
  • Android自动化测试初探

    千次阅读 2016-11-21 11:18:42
    本文内容:Android自动化测试框架初探 版权声明:本文为原创文章,未经允许不得转载 博客地址:http://blog.csdn.net/kevindgk 初步了解 什么是自动化测试 优点 缺点 前提条件 应用场景 基本原理 目前主流...
  • 自动化测试方案

    千次阅读 2021-09-24 09:52:16
    自动化测试体系方案 方案1全编写代码流程 UI自动化: 使用python或java,配合selenium库及pytest框架做UI自动化测试。(通过selenium的webdriver驱动,驱使浏览器) 1. WebDriver API(基于Java、Python) java...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 171,611
精华内容 68,644
关键字:

自动化测试业务层