编程技术类预见·自动化测试预见·软件测试技术

自动化测试(10) | Selenium Java 封装

2017-03-14  本文已影响1215人  厲铆兄

WebDriver 封装

欢迎阅读WebDriver封装讲义。本篇讲义将会重点介绍Selenium WebDriver API的封装的概念和方法,以及使用封装进行自动化测试的设计。

WebDriver API 封装

封装的概念

从之前的讲义和学习中,我们知道,WebDriver API的调用以及自动化测试,我们也初步接触了线性测试、以及模块化自动化测试和数据驱动测试,那么回顾之前的内容,我们不只是可以利用WebDriver提供的一系列的定位符以便使用元素定位方法,我们这里开始尝试封装后调用。首先,我们从封装的概念开始。

封装是一个面向对象编程的概念,是面向对象编程的核心属性,通过将代码内部实现进行密封和包装,从而简化编程。

所谓“对象”,形象地说,我们可以把它理解为一块积木。设计积木的人需要设计积木的外观与形状,还有内部的材质。堆积木的人对于内部的材质并不关心,他们只需要根据不同的外观与形状来决定堆放的位置。因此,对于开发者而言,要设计面向对象的程序,同时会是两个迥然不同的身份:设计者与使用者。

先谈谈使用者。使用者的身份,就是利用已经提供给你的所有对象,根据需求,设计出自己需要实现的程序。就如堆积木的过程。这恰恰是面向对象编程的优势所在,那就是“对象的重用”。已经设计好的对象,可以被不同的使用者调用,这些功能既然已经实现,对于使用者而言,当然就免去了自己去设计的过程。正如堆积木那样,既然有了现成设计好的积木,使用者所要做的工作就是把这些积木最后组合起来,堆成不同的形状。WebDriver所提供的类库,就是这样的积木。那么我们以下的操作将会基于上述的定位符进行定位操作。

前面说到对象好比是一个积木,设计者需要定义好这个积木的外观和形状,也要考虑积木内部的制作,例如选用的材质,以及是空心还是实心。如果将这个积木剖开来看,实际上该对象应分为内、外两层。由于使用者只关心外部的实现,因此设计者就需要考虑,哪些实现应暴露在外,哪些实现应隐藏于内。这就体现了对象的封装的思想。

简而言之,封装就是把原始和原生的方法进行再包装。将原始的代码用心的代码包装起来,通过对新代码的调用,来使用原始的代码的过程。

封装的好处

对Selenium进行封装的好处主要有如下三个方面:

封装的目的

封装,最终为了实现自动化测试框架。在自动化测试领域,有一个经典的问题:“既然可以编写或者通过record & playback可以做一个脚本,那么为什么还需要自动化测试框架呢?”简而言之,就是为什么需要如此这般麻烦的设计和编写自动化测试框架,不是原本已经可以做自动化测试了么?

这个回答可以很“官方”,从维护性、重用性、安全性和成本等角度可以回答。

在这点,就好比是建造房子。在没有设计框架的基础上,我们或许可以建造一个楼房,最多也就三两层吧;但是对于一份经过完整设计的图纸,人们可以建造出高楼大厦。

封装,就是把基础的石头等建材,通过我们的个性化的方法,将地基可用而安全的搭建好。是自动化测试框架的基石。

自动化测试模型

自动化测试模型.png
  1. 封装 Selenium 为 BoxDriver
  2. 在 测试用例中,实例化 BoxDriver,产生 bd 对象
  3. 使用 bd 对象,构造 业务模块的实例化对象,产生 common
  4. 使用 common 在测试用例中,构建测试步骤
  5. 使用数据驱动的外部数据,通过读取,进行测试
  6. 执行整个用例

使用封装进行自动化测试

封装技术

  1. 面向对象的编程
  1. 封装:做一个模板,这个模板有webdriver所有的功能
  1. 其他公司的开源框架

封装示例

测试脚本:以下的脚本

以上的代码是封装了locateElement()的几种方法,在具体使用封装过的代码的时候,只需要简单的调用即可。接下来的重点,是介绍 locateElement(selector)的封装方式。

private WebElement locateElement(String selector) {
  WebElement we;
  // 如果定位符中 有 分隔符,那么就从分隔符处分成两段
  // 第一段是By
  // 第二段是真正的定位符
  // 如果没有分隔符,就默认用 id 定位
  if (!selector.contains(this.byChar)) {
    // 用 id 定位
    we = this.baseDriver.findElement(By.id(selector));
  } else {
    // 用 分隔符 分成两个部分
    String by = selector.split(this.byChar)[0];
    String value = selector.split(this.byChar)[1];
    we = findElementByChar(by, value);
  }
  return we;
}
private WebElement findElementByChar(String by, String value) {
  WebElement we = null;
  switch (by.toLowerCase()) {
    case "id":
    case "i":
      we = this.baseDriver.findElement(By.id(value));
      break;
    case "css_selector":
    case "css":
    case "cssselector":
    case "s":
      we = this.baseDriver.findElement(By.cssSelector(value));
      break;
    case "xpath":
    case "x":
      we = this.baseDriver.findElement(By.xpath(value));
      break;
    case "link_text":
    case "link":
    case "text":
    case "linktext":
    case "l":
      we = this.baseDriver.findElement(By.linkText(value));
      break;
      //TODO: other by type
  }
  return we;
}

使用上面的封装类,就需要指定特定的 selector

类型 示例(分隔符以逗号,为例) 描述
id "account" 或者 "i,account" 或者 "id,account" 分隔符左右两侧不可以空格
xpath "x,//*[@id="s-menu-dashboard"]/button/i"
css selector "s,#s-menu-dashboard > button > i"
link text "l,退出"
partial link text "p,退"
name "n,name1"
tag name "t,input"
class name "c,dock-bottom

调用示例

void logIn(String account, String password) throws InterruptedException {
  BoxDriver driver = this.baseDriver;
  driver.type("account", account);
  driver.type("password", password);
  driver.click("submit");
  // 点击登录按钮后,需要等待浏览器刷新
  Thread.sleep(2000);
}

自动化的测试代码示例

@Test
public void test01Login() {
  common.openPage();
  common.logIn(member.getAccount(), member.getPassword());
  expectedUrl = this.baseUrl + "sys/index.html";
  Assert.assertEquals(driver.getCurrentUrl(), expectedUrl, "新用户登录失败");
  common.logOut(lang);
}

封装需要注意的部分

关于Firefox Profile的使用

在做自动化测试的时候,经常会发现Firefox 被初始化,提示收藏夹等,遮住元素窗口。因为Firefox每次都以默认的Profile 加载全新的Firefox,例如如下图片:

Snap1.jpg

在这样的情况下,我们需要专门准备一份独立的Firefox Profile进行使用。步骤如下

  1. 在命令行中进入Firefox的安装目录,然后输入 firefox -ProfileManager -no-remote

    Snap2.jpg
  2. 然后在弹出的窗口中,新建一个Profile,记录地址。

    e5792a15-e7ed-39fa-bf46-5505c54923a5.png
  3. 根据刚刚的地址,打开Profile所在的文件夹:C:\Users\Linty\AppData\Roaming\Mozilla\Firefox\Profiles

    Snap3.jpg
  4. 复制 einy9uds.selenium文件夹到 base目录中。

    Snap4.jpg
  5. 修改代码 automate_driver.py

    def __init__(self, by_char=",", firefox_profile=None):
        """
        构造方法:实例化 BoxDriver 时候使用
        :param by_char: 分隔符
        :param firefox_profile:
        可选择的参数,如果不传递,就是None
        如果传递一个 profile,就会按照预先的设定启动火狐
        去掉遮挡元素的提示框等
        """
        if firefox_profile is not None:
            firefox_profile = FirefoxProfile(firefox_profile)
            driver = webdriver.Firefox(firefox_profile=firefox_profile)
            try:
                self.base_driver = driver
                self.by_char = by_char
                except Exception:
                    raise NameError("Firefox Not Found!")
    
  6. 修改代码 xxx_test_cases.py

    profile = "base\\einy9uds.selenium"
    self.base_driver = AutomateDriver(firefox_profile=profile)
    
  7. 完毕。

上一篇下一篇

猜你喜欢

热点阅读