Web UI自动化测试系统设计

作者: 小飞侠fayer | 来源:发表于2019-03-16 16:19 被阅读155次

    1. 自动化测试简介

    1.1 什么是好的自动化测试框架

    在创建测试自动化框架时,我们应该考虑以下要点:

    1. 能够通过使用适当的抽象层快速创建自动化测试
    2. 应易于维护和扩展应该足够简单,以便测试人员编写自动化测试
    3. 该框架应具有有意义的日志记录和报告结构
    4. 重新运行失败测试的重试机制 - 这对WebDriver UI测试特别有用
    5. 对现有系统不会造成影响(setup teardowm)
    6. 最小化测试用例之间的重复 Minimize Test Overlap
    7. 每个用例之间相互独立 Keep each Test independent
    8. 将测试和产品代码分开 Keep test logic out of production code
    9. 对测试用例执行结果进行校验 Verify one condition per test

    1.2 自动化测试的基本步骤

    自动化测试的基本步骤.png
    1. Setup
      构造用例执行前的前置条件,构造执行环境
    2. Exercise
      执行用例
      3.Verification
      对执行结果进行校验
    3. Teardown
      用例执行结束后,对执行环境进行还原,使SUT回到用例执行前的状态

    1.3. 自动化测试常用的思路

    1.3.1 记录和回放Record and playback

    1. 功能
      直接录制执行过程,并回放
    2. 实现
      通过录制小工具,将用户对网页的操作过程记录保存
    3. 好处
      适合新手,上手快
    4. 缺点
      稳定性差,xpath一般是根据元素的绝对位置生成,稳定性很差
    5. 应用
      selenium、katalon等测试框架均支持相应的录制工具

    1.3.2 数据驱动Data driven

    1. 功能
      “测试数据”与“执行代码”做分离, 使用不同的输入数据测试相同的工作流程。
    2. 实现
      将不同的场景对应的参数提取出来,放在文件中,使用时,只需要遍历文件,将这些参数分别作为测试流程的入参,生成多个测试用例
    3. 好处
      可以通过导入不同的配置,设置不同的执行场景,提高复用性
    4. 坏处
      测试数据和测试流程强关联,如果新增功能,需要增加新的配置参数,增加了使用和扩展的复杂性,只适用于单个简单行为测试,不适合流程测试
    5. 应用
      robotframework中的template,katalon中data set

    1.3.3 关键字驱动Keyword driven

    1. 功能
      对页面上的操作行为进行拆分和抽象,保存为一个个具体的行为关键字。用户根据需求对关键字进行组装

    2. 实现
      将每个页面的操作行为,封装为不同的关键字函数,测试用例可调用不同关键字,组成不同的操作流程

    3. 好处
      将单个行为和系统流程拆分,减少耦合,所有的用例针对同一个行为是调用同一个函数,减少维护成本

    4. 坏处
      关键字的个数和页面功能的复杂性成正比

    5. 应用
      page object model

    2. 自动化测试设计模式

    2.1 Page Object Model

    2.1.1 为什么

        考虑这个简单的脚本登录网站:

        如图所示,我们所做的只是找到元素并为这些元素填充值。这是一个小脚本。脚本维护看起来很简单 但随着时间的推移测试套件将会增长  随着代码添加越来越多,维护将变得越来越困难。脚本维护的主要问题是,如果10个不同的脚本使用相同的页面元素,并且该元素有任何更改,则需要更改所有10个脚本。这是耗时且容易出错的。
         更好的脚本维护方法是创建一个单独的类文件,该文件可以找到Web元素,填充它们或验证它们。可以在使用该元素的所有脚本中重用此类。将来,如果Web元素发生更改,我们只需要在1个类文件中进行更改,而不是10个不同的脚本。这种方法称为页面对象模型(POM)。它有助于使代码  更具可读性,可维护性和可重用性。

    2.1.2 是什么

    Page Object Model是一种为Web UI元素创建Object Repository的设计模式。在此模型下,对于应用程序中的每个网页,应该有相应的页面类。此Page类将查找该Web页面的WebElements,还包含对这些WebElements执行操作的Page方法。这些方法的名称应根据它们正在执行的任务给出,即,如果加载程序正在等待显示支付网关,则POM方法名称可以是waitForPaymentScreenDisplay()。

    关于页面对象是否应该包含断言本身,或者仅为测试脚本提供数据以进行断言,存在意见分歧。
    在页面对象中包含断言的倡导者说,这有助于避免在测试脚本中重复断言,使得更容易提供更好的错误消息,并支持更多的TellDontAsk样式API。
    无断言页面对象的倡导者说,包含断言将提供对页面数据的访问权限与断言逻辑混合在一起,并导致一个膨胀的页面对象。
    我赞成在页面对象中没有断言。我认为您可以通过为常见断言提供断言库来避免重复 - 这也可以使提供良好诊断更容易。页面对象通常用于测试,但不应自行进行断言。他们的职责是提供对底层页面状态的访问。由测试客户端来执行断言逻辑。

    2.1.3 好处

    1. 页面对象模式表示UI中的操作和流程应与验证分开。这个概念使我们的代码更清晰,易于理解。
    2. 对象存储库独立于测试用例,因此我们可以使用相同的对象存储库用于不同的工具。例如,我们可以将POM与TestNG / JUnit集成用于功能测试,同时与JBehave / Cucumber集成以进行验收测试。
    3. 由于POM类中可重用的页面方法,代码变得更少并且得到优化。
    4. 方法获得更真实的名称,可以通过UI中的操作轻松映射。即如果点击我们登陆主页的按钮后,方法名称就像'gotoHomePage()'。

    2.1.4 实现

    简单的例子:


    详细的例子:

    步骤1)转到Guru99演示站点


    步骤2)在主页检查文本“Guru99 Bank”存在


    步骤3)登录应用程序


    步骤4)验证主页是否包含“Manger Id:demo”


    功能中包含两个页面:

    1. 登录页面
    2. 主页(登录后显示)
      因此,我们创建了2个POM类

    1. Login page POM

    import org.openqa.selenium.By;
    
    import org.openqa.selenium.WebDriver;
    
    public class Guru99Login {
    
    WebDriver driver;
    
    By user99GuruName = By.name("uid");
    
    By password99Guru = By.name("password");
    
    By titleText =By.className("barone");
    
    By login = By.name("btnLogin");
    
    public Guru99Login(WebDriver driver){
    
        this.driver = driver;
    
    }
    
    //Set user name in textbox
    
    public void setUserName(String strUserName){
    
        driver.findElement(user99GuruName).sendKeys(strUserName);
    
    }
    
    //Set password in password textbox
    
    public void setPassword(String strPassword){
    
         driver.findElement(password99Guru).sendKeys(strPassword);
    
    }
    
    //Click on login button
    
    public void clickLogin(){
    
            driver.findElement(login).click();
    
    }
    
    //Get the title of Login Page
    
    public String getLoginTitle(){
    
     return    driver.findElement(titleText).getText();
    
    }
    
    /**
    
     * This POM method will be exposed in test case to login in the application
    
     * @param strUserName
    
     * @param strPasword
    
     * @return
    
     */
    
    public void loginToGuru99(String strUserName,String strPasword){
    
        //Fill user name
    
        this.setUserName(strUserName);
    
        //Fill password
    
        this.setPassword(strPasword);
    
        //Click Login button
    
        this.clickLogin();        
    }
    

    }

    2. Home Page POM;

    import org.openqa.selenium.By;
    
    import org.openqa.selenium.WebDriver;
    
    public class Guru99HomePage {
    
    WebDriver driver;
    
    By homePageUserName = By.xpath("//table//tr[@class='heading3']");
    
    
    
    public Guru99HomePage(WebDriver driver){
    
        this.driver = driver;
    
    }
    
    //Get the User name from Home Page
    
        public String getHomePageDashboardUserName(){
    
         return    driver.findElement(homePageUserName).getText();
    
        }
    

    }

    3. 测试用例

    import java.util.concurrent.TimeUnit;
    
    import org.openqa.selenium.WebDriver;
    
    import org.openqa.selenium.firefox.FirefoxDriver;
    
    import org.testng.Assert;
    
    import org.testng.annotations.BeforeTest;
    
    import org.testng.annotations.Test;
    
    import pages.Guru99HomePage;
    
    import pages.Guru99Login;
    
    public class Test99GuruLogin {
    
    WebDriver driver;
    
    Guru99Login objLogin;
    
    Guru99HomePage objHomePage;
    
    @BeforeTest
    
    public void setup(){
    
        driver = new FirefoxDriver();
    
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    
        driver.get("http://demo.guru99.com/V4/");
    
    }
    
    /**
    
     * This test case will login in http://demo.guru99.com/V4/
    
     * Verify login page title as guru99 bank
    
     * Login to application
    
     * Verify the home page using Dashboard message
    
     */
    
    @Test(priority=0)
    
    public void test_Home_Page_Appear_Correct(){
    
        //Create Login Page object
    
    objLogin = new Guru99Login(driver);
    
    //Verify login page title
    
    String loginPageTitle = objLogin.getLoginTitle();
    
    Assert.assertTrue(loginPageTitle.toLowerCase().contains("guru99 bank"));
    
    //login to application
    
    objLogin.loginToGuru99("mgr123", "mgr!23");
    
    // go the next page
    
    objHomePage = new Guru99HomePage(driver);
    
    //Verify home page
    
    Assert.assertTrue(objHomePage.getHomePageDashboardUserName().toLowerCase().contains("manger id : mgr123"));
    
    }
    

    2.1.5 扩展

    Page Factory是Selenium WebDriver的内置页面对象模型概念,但它已经过优化。在这里,我们遵循页面对象存储库和测试方法的分离概念。另外,在PageFactory类的帮助下,我们使用@FindBy注释来查找WebElement。我们使用initElements方法初始化Web元素

    @FindBy可以接受tagName,partialLinkText,name,linkText,id,css,className,xpath作为属性。让我们使用Page Factory查看与上面相同的示例

    2.2 BDD (Behavioral Driven Development)

    2.2.1 为什么

    软件开发中常见的浪费活动包括:

    1. Dev/QA/BA对需求理解不一致,由于误解或模糊的要求导致的返工
    2. 由于不愿意重构代码而导致的技术债务
    3. 孤岛和交接造成的反馈周期缓慢

    低行为的沟通可能是使用BDD的最大优势,使技术团队和非技术团队之间的协作能够以更高的效率运行。用通用语言编写的BDD测试用例的优点是所有人都可以容易地理解应用程序的行为方式。例如,可以使用实际需求的实时示例编写测试用例,以解释系统的行为,减少误解。

    能更方便的会用例进行管理

    2.2.2 是什么

    行为驱动开发(BDD)是一种从TDD(测试驱动开发)发展而来的软件开发方法。它的不同之处在于用共享语言编写,这改善了技术与非技术团队和利益相关者之间的沟通。在这两种开发方法中,测试都是在代码之前编写的,但在BDD中,测试更加以用户为中心,并且基于系统的行为。设计要求为:

    1. 需求应转换为可定义具体示例的用户故事。
    2. 每个示例都应该是有效的用户场景,而不仅仅是测试用例。

    2.2.3 应用

    'Given-When-Then'公式
    这是为用户故事编写BDD测试用例的建议模板,可以定义为:

    • 给定某种情况

    • 当一个动作发生时

    • 那么这应该是结果。

    一个实际的例子是:

    • -由于用户没有输入窗体上的任何数据。

    • 当他们点击提交按钮

    • 然后显示验证成功的消息

    2.2.4 好处

    1. 不再定义'测试',而是定义'行为'。
    2. 开发人员,测试人员和产品所有者之间更好的沟通因为使用简单语言解释BDD,学习曲线将更短。
    3. 它本质上是非技术性的,可以覆盖更广泛的受众。
    4. 行为方法在开发之前定义了验收标准。

    2.2.5 坏处

    1. 要在BDD工作,需要先前的TDD经验。
    2. BDD与瀑布式方法不兼容。
    3. 如果未正确指定要求,BDD可能无效。
    4. 使用BDD的测试人员需要具备足够的技术技能。

    3. 自动化系统设计实例

    3.1 为什么要分层

    1. 用户在对web UI进行测试时,一般会包含多个Page(功能页面),每个Page都有自己的UI元素和行为操作,各个Page之间相互不干扰,需要分离。

    2. 在新增用例的时候,每个用例设计时都需要考虑配置信息、页面元素信息、行为操作、具体流程设计。不同用例之间的配置信息、页面元素信息、行为操作会有重叠部分,只是流程上会有差异,因此,需要将业务操作和测试用例分离,进行分层设计。

    因此,测试系统设计可采用Page Object Model设计模式,以用户登陆为例,可以分成以下几个层次:

    Page层:完成单个页面页面元素、页面行为的配置,包括CommonPage基本页面层、PageElement页面对象层、ActionOperator行为操作层。
    Workflow TCs:完成单个页面的行为流程和校验的test cases,该test case不能直接执行,只能被真正Main TCs引用。
    Main TCs:真正执行的测试用例
    Test Suite:测试用例集合
    Data-bingding:测试系统所需的配置数据

    3.2 Data-binding 数据配置层

    功能: 完成系统配置,如:web服务地址、用户名、密码、git/p4地址等信息
    实现:

    1. katalon本身支持dataMap,可以上传excel/csv文件,该文件可以被多个testcase同时复用
    2. 配置全局的Execution Profile,此时变量可以在各个case中使用
    3. case 可以设置全局变量和case 内部的变量

    3.3 Page层

    完成单个页面页面元素、页面行为的配置

    3.3.1 CommonPage基础页面层

    功能: 完成Page交互时的通用功能,如:点击、切换到frame、拖动滚动条、元素获取等. 该层是Page最底层,可供ActionOperator行为操作层调用

    实现:定义CommonPage,调用katalon WebUI对应的接口,实现上述功能。

    3.3.2 PageElement页面对象层

    功能:保存不同page的元素path。当页面元素变更了,直接修改单个元素,不存在测试用例维护问题。

    实现:新建Object Repository, 按照page划分目录,对每个page的元素Xpath/Css/Arribute进行配置

    3.3.3 ActionOperator行为操作层

    功能:对每个Page用户独立的行为操作进行封装,如:登陆、新增workspace等。将业务操作与测试用例分离,因为多个用例可能是对应一个业务操作的,这样,我业务代码ji'hu,只需要修改用例就好了。

    实现:继承于 CommonPage,实现各个页面独有的所有行为(不包括校验)。每个页面的元素,引用于 PageElement页面对象层

    命名:

    • 应该尽可能具有描述性名称
    • 清晰解释这个关键字是做什么的,而不是怎么做的,是抽象级别的(譬如:Input Text或者Administrator logs into system)
    1. 去掉后缀下划线换成空格
    2. 如果名字全部小写,单词首字母换成大写名字可能适当加长
      Good:
      Login With Valid Credentials

    Bad:
    Input Valid Username And Valid Password And Click Login Button

    3.4 WorkFlow TCs 工作流程层

    功能:对每个page可能的页面流程进行设计并校验。

    实现: 引用ActionOperator行为操作层,将页面流程封装称测试用例

    3.5 TestCase测试用例(Main TCs)

    功能:完成具体测试用例

    实现 : 调用WorkFlow工作流程层,进行流程组装

    命名:

    • 应该尽可能具有描述性名称
    1. 去掉后缀下划线换成空格
    2. 如果名字全部小写,单词首字母换成大写名字可能适当加长

    例子:
    Login With Empty Password Should FailLogin With Empty Username Should FailLogin With Empty Username And Password Should FailLogin With Invalid Username Should FailLogin With Invalid Password Should FailLogin With Invalid Username And Invalid Password Should Fail

    3.6 TestSuit测试用例套件层

    功能:每个testSuit中包含多个测试用例,可对testcase进行分组,指定待执行的测试用例。
    实现:配置test suit
    命名:

    • 应该尽可能具有描述性名称
    1. 去掉后缀下划线换成空格
    2. 如果名字全部小写,单词首字母换成大写名字可能适当加长
      举例:login_tests.robot -> Login Tests
      IP_v4_and_v6 -> IP v4 and v6

    3.7 Log日志层

    功能: 保存测试用例中运行过程中的日志、截图。

    实现:

    1. 采用katalon本身的日志打印,KeywordUtil.logInfo(String message). 而不是Print函数
    2. webUi.takeScreenshot()可以直接截图
      3.katalon支持配置录屏功能

    3.8 Report报告层

    功能: 保存执行结果。
    实现:katalon默认会生成每个test suit执行结果

    3.9 SetUp 和 TearDown

    功能:为每个测试用例/用例集提供用例执行的前置配置和后置配置
    实现:

    1. 每个testcase内部支持自定义method

    2. testsuits中的script模式下可进行基于每个testcase和每个testsuit下的通用配置。

    3. Test Listeners支持全局范围内的配置。

    执行顺序如下:

    参考文档

    page object model

    相关文章

      网友评论

        本文标题:Web UI自动化测试系统设计

        本文链接:https://www.haomeiwen.com/subject/zdcsmqtx.html