来源:测试开发探秘公众号

一、用到的工具和语言

1)Selenium IDE:作为火狐的一个插件,是我们Web自动化测试中必不可少的。

 

(2)FireBug:火狐的一个插件,帮助我们定位页面元素。

 

(3)Eclipse:强大的代码编辑工具,相信大家并不陌生。

 

(4)PyDev:Eclipse的插件,用于编辑Python代码。

 

(5)Python:我们测试用例的编码语言,请自行学习,本系统教程是不再讲究Python编程的内容。

 

(6)WebDriver:selenium2.0,Web自动化测试主要框架。

二、环境搭建&工具安装
Selenium安装

方法一,安装Selenium IDE的步骤如下:

 

Ø  从www.openqa.org/selenium-ide/download.action下载Selenium IDE(一个XPI后缀的文件)。

 

Ø  启动FIREFOX浏览器,打开刚才下载的文件。

 

Ø  重启FIREFOX浏览器,在工具菜条下应该就可以看到Selenium IDE菜单项。

 

方法二,从Firefox浏览添加

 

Ø 打开浏览器,打开菜单“工具”à“附加组件”,在打开的页面搜索Selenium。

 

Ø 安装Selenium IDE Button,安装完成的重启浏览器。

 

Ø 定制工具栏,将Selenium IDE Button拖到工具栏上,然后单击这个Button,按提示安装Selenium IDE,这个时候选择最新的版本即可。

 

注:Selenium IDE安装完成后,默认打开了所有支持语言的格式,如图2.1.2所示,我们可以禁用到不用的语言项。

图2.1.2 Selenium IDE支持的语言格式

 

FireBug安装

      FireBug的安装和使用,可以参考这个文档:http://jingyan.baidu.com/article/fd8044fa97e08c5030137a6c.html,此文档把FireBug的基本使用方法都介绍了一下,还是比较详细的

WebDriver Python开发环境搭建

 

   上面是所用到的工具的介绍,下面我们开始着手搭建WebDriver+Python在windows下的运行环境。

 

2.3.1 工具选择

Ø  操作系统:Windows 7 64位。

 

Ø  Python版本: 选择2.7.X。目前大部分第三方库和工具对2.7都有简单的安装包,不需要自己做太多处理,比2.6内置了一些包,不需要再安装; Python3.x不支持Selenium2.0。

 

Ø  Selenium版本:python自动安装最新的包,如果手动安装不能低于2.0,因为从2.0开始,Selenium已经和WebDriver集成在一起了,WebDriver提供了非常多的API和自动化测试处理方法。

 

Ø  脚本开发工具:Eclipse(JDK:选择1.6版本),其中插件选择:PyDev,专门对python进行开发。

 

2.3.2 Python+Webdriver安装

 

    请按以下步骤安装python+Webdriver运行环境:

 

第一步:安装Python

 

Ø  根据下面的地址,直接一键安装,全部默认方式。

 

下载地址:http://www.python.org/ftp/python/2.7.2/python-2.7.2.msi

 

Ø  设置Python的环境变量:,修改我的电脑->属性->高级->环境变量->系统变量中的PATH为PATH:“C:\Python27;”

 

上述环境变量设置成功之后,就可以在命令行直接使用python命令。或执行"python *.py"运行python脚本了。

 

Ø  此时,还是只能通过"python *.py"运行python脚本,若希望直接运行*.py,只需再修改另一个环境变量PATHEXT为:PATHEXT=PATHEXT;.PY;.PYM

 

第二步:安装Python的SetupTools

 

其实SetupTools就是一个帮助你安装第三方工具包的增强工具软件,根据下面的地址下载,然后一键安装。下载地址:

 

http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11.win32-py2.7.exe#md5=57e1e64f6b7c7f1d2eddfc9746bbaf20

 

第三步:安装Python的包管理工具

 

pip有点类似SetupTools ,打开DOS界面,进入到目录:C:\Python27\Scripts,然后敲入命令: easy_install pip, 等待完成就OK。如图2.3.2.1所示:

图2.3.2.1 pip安装过程

 

第四步:安装基于Python的Selenium包

 

打开DOS界面,进入到目录: C:\Python27\Scripts,然后敲入命令: pip install selenium,回车后就会自动下载最新的selenium包,并进行安装。

 

第五步:验证Selenium安装是否成功

 

在记事本中编写下面的代码:(保存为 pytest.py,然后直接运行即可!)

 

#pytest.py

 

from selenium import webdriver

 

browser=webdriver.Firefox()#获取本地火狐浏览器

 

browser.get("http://www.baidu.com")#打开百度首页

 

assert "Yahoo!" in browser.title

 

 

 

browser.close()

 

将上面代码保存,然后在命令行下找到此文件,python pytest.py运行。如果能成功打开火狐浏览器,并打开了百度首页,则说明Selenium安装成功。

 

2.3.3 Eclipse python开发环境配置

     

      Eclipse是强大的开发工具,所以我们也采用这个工具编写我们的自动化测试用例。其插件pydev,更能方便地编辑和运行python脚本文件。下面我们就开始配置这个开发环境:

 

第一步:安装JDK6、Eclipse

 

注:JDK和Eclipse都要用64位,否则有可能遇到问题。

 

JDK需要配置环境变量(详细见http://jingyan.baidu.com/article/6dad5075d1dc40a123e36ea3.html

 

下载JDK:http://download.csdn.net/download/xiaoxiaoxinyuan8/5796753

 

eclipse下载:

 

http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/indigo/SR1/eclipse-java-indigo-SR1-win32-x86_64.zip

 

     当然你也可以自行在网上搜索下载,JKD最好用6,不过好像8也支持。可能尝试用最新版本 ,如果有问题,就降下来,毕竟低版本用的时间长,比较稳定,但也存在不包括最新的功能的风险。

 

第二步:给Eclipse安装PyDev插件

 

    启动Eclipse ,在Help菜单中,选择Install New Software•••,

 

     选择Add按钮,Name:PyDev,Location:http://pydev.org/updates(PyDev的更新地址),单击OK,开始查询。如图2.3.3.1所示:

图2.3.3.1 安装Pydev插件

 

    然后在打开的对话框中选择PyDev下的PyDev for Eclipse,别的都不要选,否则依赖检查那关过不去。如图2.3.3.2所示:

图2.3.3.2 pydev安装项选择

 

    点下一步安装,中间会出现是否信任Aptana、Pydev,选择信任即可,最后重启Eclipse(如果第二步不能成功,尝试从官网上下载Pydev2.8.1版本,直接覆盖到纯净版eclipse插件文件夹下,重启eclipse即可)。

 

    另外需要下载MySQL-python.rar插件,直接安装,重启eclipse。不同的环境和版本可能会出现不同的问题,大家需要去网上查询相关的解决办法,在此就不一一穷尽。

 

第三步:配置PyDev插件

 

    在Window–Preference–PyDev–Interpreter-Python,单击New...按钮,在弹出的Select interpreter窗口中单击Browse...按钮,找到已经安装的Python解释器。如图2.3.3.3所示:

图2.3.3.3 选择python解释器

 

     单击Select interpreter窗口中单击OK按钮,在弹出的Selection Needed窗口中单击Select All按钮,然后单击OK按钮完成设置。如图2.3.3.4所示:

图2.3.3.4 选择所有相关内容

 

     然后在Preferences窗口中选择Apply—>OK完成设置。如图2.3.3.5所示:

图2.3.3.5 应用所有配置

 

第四步:配置Python编码格式

 

    统一编码格式,把PyDev的编码格式修改成UTF-8,默认采用GBK编码。取消u' ...'形式的unicode文本表示,保存文本的数据类型是str,保存数据的数据类型是bytes。由于默认采用utf-8编码,只要保持.py文件的字符编码也为utf-8格式,不用再在头部声明程序的编码类型,即不用写# -*- coding: utf-8 -*-;采用如下方法:

 

Ø  修改PyDev编码格式,在Window-->Preferenceà General->Editors->Text Editors->Spelling,Encoding改成Other:UTF-8 。

 

Ø  修改Workspace编码格式General->Workspace,Text file encoding改成Other:UTF-8 。

 

Ø  修改python编码格式:找到安装目录下的\plugins\org.python.pydev.debug_x.x.x.yyyymmddhh\pysrc\pydevd.py, 920行的 encoding = Non 改成 encoding = "UTF-8",保存 (有的环境可能没有这个文件,如果找不到就忽略)。

 

至此,PyDev的配置就完成了。

 

注:如果没有配置编码规范,运行python脚本时会报错。

 

第五步:测试安装是否成功

 

    File->New->Project,选PyDev下的PyDev Project,Grammer和Interpreter选相应的版本(如2.7),单击Finish。如图2.3.3.6所示:

图2.3.3.6创建pydev工程

 

     在PyDev Package Explorer的项目上右键,New->PyDev Module,随便写个名字,Finish。 然后随便写几行代码,Run 在弹出的对话框中选择Python Run,如果运行成功,则说明Pydev环境配置没有问题。如图2.3.3.7所示:

图2.3.3.7检测Pydev环境

 

三、8种元素定位方法

Webdriver 介绍

https://www.cnblogs.com/fnng/archive/2013/06/16/3138283.html

四、借助工具定位元素

工具使用定位

经过上面四步我们已经可以定位页面上的元素了,不过这都是通过我们人工来查看的,然后手动编写的代码。有没有更加简单的方法来定位呢?答案是Yes,就是我们前面提到的FireBug和Selenium IDE。下面我们简单地介绍一下使用方法:

(1)  Firebug提取元素的 Xpath,Css路径。

元素的 id,name,class 属性一目了然,直接可以使用,如果元素没有这几个属性,就需要用 Xpath和 Css路径定位了。但是这两个路径不太容易写出来,所以 Firebug提供了方法。

首先,我们用 Firebug  找到要定位的元素。然后右击这个元素在

Firebug中的位置,从弹出的菜单中选择“复制Xpath”,“复制最简

 

Xpath”或是“复制 CSS 路径”。最后将复制到的内容粘贴出来,这就是对应页面元素的xpath 或是 Css 路径。如图 3.2.2.2 所示:

 

图 3.2.2.2 提取页面元素的 CSSor Xpath 路径

(2)    SeleniumIDE验证提取的路径是否正确。

通过 Firebug 我们可以提取出元素的Css 或者 Xpath 的路径, 可是提取的究竟对不对呢?工具有的时候也不太靠谱,所以我们要验证一下。最直接的办法就是放到测试用例中去执行一下,但是一直在执行测试用例,这样比较耗时。我们可以借助于 SeleniumIDE来验证一下。

验证方法如下:

  • 用 FireBug提取出要定位的元素的 Xpath或者 Css路径。
  • 打开SeleniumIDE界面,右击界面“Insertnewcommand”。
  • 将复制的路径粘贴到 IDE的 Target文本框中,如果复制的是

Css路径,需要在复制的路径前加上“Css=”。

  • 单击Find按钮,此时 Firebug中显示的要定位的元素会标黄显示,表示定位正确。如图3.2.2.3所示:

 

 

图 3.2.2.3 验证定位元素正确的情况

  • 如果复制的路径不对,则IDE会在 log区以红色的信息提示定位不到。如图 3.2.2.4所示:

 

 

图 3.2.2.4 验证定位元素定位不到的情况

 

注意:

Firebug提交的路径一般都是从页面起始位置<html>标签开始, 一直提取到要定位的元素,是相对路径,容易受到网页变化的影响。不建议直接使用,只可以作为参考。

五、Xpath 定位方法深入探讨

      相比 cssSelector,xpath 是我比较常用的一种定位元素的方式,因为它很方便,缺点是,消耗系统性能。如果 Xpath 使用的比较好,几乎可以定位到任何页面元素,而且受页面变化影响较小。

 

(1)常用的 Xpath 定位方法及其特点

 

  • 使用绝对路径定位元素。

例如:driver.find_element_by_xpath ("/html/body/div/form/input")。特点:这个路径是从网页起始标签<html>开始一直到要定位的元

素的路径,如果要定位的元素在页面最下面,则这个 Xpath 路径会非常长。如果在要定位的元素与页面开始之间的元素有任何增减,元素定位就会失败。

 

  • 使用相对路径定位元素。

例如:driver.find_element_by_xpath ("//input")       返回查找到的第一个符合条件的元素。

特点:相对路径一般只会包含与被定位元素最近的几层元素有关,相对路径写的好的话,页面变动影响最小,而且定位准确。

 

  • 使用索引定位元素,索引的初始值为 1,注意与数组等区分开。

例如:driver.find_element_by_xpath ("//input[2]") 返回查找到的第二个符合条件的元素。

特点:如果一个页面中有多个相似的元素,或是一个层下面有多个同样的元素的时候,需要用索引的方法来定位,否则无法区分。

 

  • 结合属性值来定位元素。

例如:driver. find_element_by_xpath ("//input[@id='username']"); driver. find_element_by_xpath ("//img[@alt='flowr']");

特点:属性定位也是比较常用的方法,如果元素中没有常见的id,name,class 等直接有方法可调用的属性,也可以查找元素中是否有其他能唯一标识元素的属性,如果有,就可以用此方法定位。

 

  • 使用逻辑运算符,结合属性值定位元素,and 与 or。

例如:driver. find_element_by_xpath ("//input[@id='username' and @name='userID']");

特点:多个属性值联合定位,更能准确定位到元素。并且如果多个相同标签的元素,如果其包含的属性值有不同的,也可以用这个方法区分开来。

 

  • 使用属性名来定位元素。

例如:driver. find_element_by_xpath ("//input[@button]")

特点:此方法可以区分同一种标签,含有不同属性名的元素。定位相对简单一些儿,但也同样存在着无法区分同种标签含有同种属性名的多个元素,这个时候要配合索引定位才行。

 

  • 类似于  cssSlector,使用部分属性值匹配元素.

例如:

(a)starts-with()

driver. find_element_by_xpath ("//input[stars-with(@id,'user')]")

(b)ends-with()

driver. find_element_by_xpath ("//input[ends-with(@id,'name')]")

(c)contains()

例如:driver. find_element_by_xpath

("//input[contains(@id,"ernam")]")

特点:此方法更加灵活,可以定位属性值不太规律,或是部分变动, 中间有空格的情况。注:如果属性值中间包含空格,Webdriver 定位的时候容易出错,时而能定位到时而定位不到,所以应该避免用含用空格的属性值定位。可以采用此方法,进行部分属性值定位。

 

  • 使用任意属性值匹配元素。

例如:driver. find_element_by_xpath ("//input[@*='username']")

特点:此方法相当于模糊查询,只要欲定位的标签,如 input 中任何属性值等于‘username’,就能匹配成功。缺点,可能会匹配含有这个属性值的其他元素,所以我们在定位的时候要查看一下这个元素值在页面中是否唯一。

 

(2)运用 Xpath 定位元素的思路

 

     当我们在做自动化测试的时候,欲对一个页面元素定位,通过上面我们讲到的选择定位方法筛选后,决定用 Xpath 定位了,此时我们应该怎么写 Xpath 呢?请按以下步骤来分析:

(a)先看一个这个元素是否有明显的,唯一的属性值。如果有 ,我们就用相对路径加属性值定位,这是最简单准确的定位方法。如://input[@alog-alias=’search’]。

(b)如果要定位的元素,不符合上面的特症,元素属性要么是动态的,要么就是不能区分这个元素的,还有就是属性值中间有空格的情况,都无法定位。所以从此元素开始,向他的上一层查找。

(c)当遇到了一个符合条件的元素时,对其写 Xpath,然后在Selenium IDE 中验证是否能定位到该元素。如://div[@type=’good’], 在 Selenium IDE 中验证能定位到这个 div。

(d)然后从这个元素开始,一级级往下写,真到要定位的元素为止。如果你比较肯定写的是正确的,可以写完后再验证,如果不肯定,就写一层, 用 Selenium IDE 验证一下, 以确保安全。如: //div[@type=’good’]/div/input

(e)当 Selenium IDE 定位成功后,再放到测试用例中去调试运行。虽然 Selenium IDE 能定位到的代码也能定位到,不过还有因为延迟,操作顺序等会影响代码定位的因素存在。

 

六、元素定位不到的原因及解决办法

 

    在我们编写自动化测试用例的过程中,经常会遇到元素定位不到的现象,有的时候我们用 Selenium IDE 检查的时候也能在Firebug 中看到,可是运行代码的时候,总是提示元素找不到。经过我以往和经

验和大家在网上的讨论,我总结了以下几种情况:

 

(1)定位属性值是动态变化的情况

现象:在我们定位元素的时候,发现有 id, name 或其他的属性存在,于是就用相应的定位方法去定位。可是运行的时候提示定位不到,然后我们再去查看元素的时候,发现属性值和我们写代码的时候不一样了。

原因:通常产生这种情况的原因就是你使用的属性值是动态变化的,主要表现有属性值是一串数据,或是字符加一串数据等情况。页面加载一次变化一次,每次都不相同。

解决办法:我们应尽量避免用这样的属性值去定位,而采用这个元素下的其他固定不变的属性值。或是向上层查找,采用 Xpath 定位。

 

(2)Iframe 中的元素定位出错的情况

现象:我们在定位元素的时候,查看网页源码,发现有 iframe 存在。可是我们没有做特殊处理,而是直接用通用的定位方法,name ,id, xpath 或者 CSS 来定位。用 Selenium IDE 验证能查找到元素,可是运行测试用例的时候,总是元素找不到。

原因:在我们运行测试脚本的时候,代码获取的是页面的句柄, 而 iframe 在句柄中是当成一个元素来处理的。脚本是没有办法自己去iframe 中去定位元素的,所以当搜索完页面时,发现找不到要定位的元素,就当错误处理。

解决办法:当需要定位 iframe 中的元素的时候,先将句柄切换到

iframe 中(driver.switchTo().frame("framename");),然后再去定位,就能定位到要测试的元素。

 

(3)不同页面或 iframe 切换时元素定位情况

现象:当我们在编写测试用例的时候,会遇到打开一个新页面, 或是切换到一个新的 iframe 中,然后再去定位元素进行操作。但是我们的定位方法写的没有问题,而且在 Selenium IDE 中也验证通过,可是代码运行的时候还是会提示找不到元素。

原因:其实这个和定位 iframe 中元素的情况是一样的,在打开一个页面或是切换到一个 iframe 的时候,driver 获取的是当前页面或是iframe 的句柄。当你的操作切换到新的页面或是 iframe 的时候,如果代码不去做相应的切换,查找元素的时候还会在原来的句柄下查找, 当然会出现查找不到的情况。

解决办法:当操作切换页面或是 iframe 的时候,我们的测试脚本

也要做相应的切换,选择新打开的页面或是切换到新的 iframe 下。然后再去定位的时候,就会在新页面或是iframe 下定位了。

 

(4)Xpath 编写出错的情况

现象:如果我们对一个元素编写了对应的 Xpath,然后在没有通过 Selenium IDE 进行验证的情况吧,就去编写代码执行测试用例。会出现查找不到元素的情况,或是页面发生了变化,导致 Xpath 路径有了变化,也会查找不到元素。

原因:主要的问题就是 Xpath 编写出错了,或是页面有改动。不管是增加了新的模块或是隐藏的 div,都会影响 Xpath 路径的。

解决办法:将代码中的 Xpath 拷出来,放到 Selenium IDE 中进行验证。如果出错了,就做相应的修改。这个也是代码维护中当遇到的问题,被测试对象变化,导致测试用例的修改。

 

(5)操作速度过快,被定位的元素没有加载出来的情况

现象:在测试用例运行过程中,会出现被定位的元素有的时候能定位的到,有的时候却定位不到的现象。而我们去页面上验证我们的定位方法的时候,没有一点儿问题,显示不是定位方法写错了。

原因:这种情况多半是因为测试用例执行到代码的时候,被定位

 

元素没有加载出来造成的。网速原因,执行代码的机器原因,都会造成加载比程序执行的慢的情况。

解决办法:在我们定位元素之前,评估一下页面的加载情况,如果有加载慢的地方,需要添加一定等待时间 self.sleep(5000),等上几秒后再去定位操作。

 

(6)定位页面嵌入式元素的情况

现象:在页面中会有一些儿嵌入式元素,如 object,播放器等。这个时候,我们对其操作的时候,是无法定位到上面的元素的。

原因:嵌入式元素对 webdriver 来说是一个元素,不管里面包含多少元素,都无法操作。对于 object 对象,网上有说要对相应的 Flash 重新编译,添加相应的代码或是控件才能定位。但这样一样又不安全了,所以嵌入式对象一直是自动化测试的盲区。

解决办法:嵌入式对象如果是简单的单击操作,可是用模拟鼠标单击相应的区域,就能完成操作。如果是输入操作,我们可以先模拟点击输入区,然后模拟键盘进行输入。除此之外,好像也没有什么好的办法。

 

(7)firefox 安全性报错的情况

现象:firefox 安全性强,不允许跨域调用出现报错,错误描述:uncaught exception: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMNSHTMLDocument.execCommand]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location:

原因:这是因为 firefox 安全性强,不允许跨域调用。

解决办法:Firefox  要取消 XMLHttpRequest 的跨域限制的话,第一是从 about:config 里设置 signed.applets.codebase_principal_support

= true; (地址栏输入 about:config 即可进行 firefox 设置)。

第二就是在 open 的代码函数前加入类似如下的代码:

try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");

}

catch (e)

{

alert("Permission UniversalBrowserRead denied.");

}

对错误进行处理。

七、检查点的设置

   

     自动化测试不像手工测试,在执行测试用例的过程中,我们可以随时看到结果,然后能判断正确与否。而自动化测试对应的就是检查点,如果不设置检查点,只有测试步骤的自动化测试是没有任何作用的。因为执行步骤执行完了,结果不是我们想要的时候,测试用例也是正确的。所以检查点才是自动化测试执行成功或是失败的检验标准,而检查点的设置是发现Bug的关键。

 

3.3.1 常用的检测点设置方法

  

      我们通过了一系列的操作后,就需要检查测试执行的结果,常用的就是Assert相关的函数。下面我们谈一下最常用的两种方法:

 

(1)手工设置检测点

     在我们测试用例执行完成之后,对测试结果进行检测。我们还是个例子来说明一下:

例子:在众筹网上喜欢一个项目,在进行了一系列的喜欢操作后,我们要检测操作是否成功。

Ø  进入到“喜欢的项目”列表页,检查是否有刚刚喜欢的项目。

Ø  我们可以直观地看到有喜欢的项目,可是怎么用程序判断呢?如图3.3.1.1所示:

图3.3.1.1 检查喜欢的项目

Ø  我们要先定位项目名称“Girls Summit组合首张EP众筹”对应的Xpath:“//div[@class='m-location']/table/tbody/tr[2]/td/div/div/p/a”,然后获取这个元素对应的Text。

Ø  将获取到的Text与“Girls Summit组合首张EP众筹”字符串进行assertEquals(),如果相同,则说明喜欢成功。否则,喜欢操作失败。

Ø  同样方法验证一下日期是不是今天,如果不是,可能是先前喜欢的操作,测试用例仍然失败。

 

(2)Selenium IDE设置检测点

      我们也可以用Selenium IDE录制测试用例,在操作完成后,需要添加检测点,此时只要利用Selenium IDE提供的“Show all Available Commands”菜单选择合适的检测点即可。

例如:同样是上面的那个喜欢项目操作的例子,我们的设置步骤如下:

Ø  进入到“喜欢的项目”列表页,检查是否有刚刚喜欢的项目。

Ø  如图3.3.1.2所示,右击项目名称,选择“Show all Available Commands”菜单,然后在打开的子菜单中选择合适的Assert菜单。

图3.3.1.2 selenium IDE设置检测点

Ø  然后Selenium IDE中就会出现相应的assert命令,如图3.3.1.3所示:

图3.3.1.3 Selenium IDE记录Assert操作

Ø  转化成相应的编码,如python,就可以直接拷到测试用例中使用。转化后的编码如:self.assertEqual(u"Girls Summit组合首张EP众筹", driver.find_element_by_link_text(u"Girls Summit组合首张EP众筹").text)

 

3.3.2 检测点设置技巧

 

      正如我们上面所说的,好的检测点是发现Bug的关键。但是并不是说检测点设置的越多越好,因为检测点会消耗机器资源,测试用例出错的时候增加排查难度。所以如何设置检测点呢?通常可以参考如下方法:

 

(1)根据测试用例的侧重点设置检测点

      每个测试用例都有测试的重点,比如说,我们测试登录的时候,登录是否成功,就需要检测。但是在我们测试喜欢项目的时候,需要先登录,这个时候登录就不需要设置检测点了,因为在登录测试用例中已经测试过了。

 

(2)设置检测点要全面

       我们在编写测试用例的时候,一定要全面了解测试操作影响了哪些儿方面。对影响到的地方,都设置一下检测点,防止出现遗漏的地方。

 

(3)设置检测点要灵活

     设置检测点的时候,我们通常会比较一下实际的结果和预期结果是否相同。可是有些儿时候,我们不能简单地进行是否相等来判断。比如说:检测图片的时候,可能会检测图片是否显示;有的检测对象在某些儿页面会换行或是添加空格,与预期有变化,这个时候我们可以判断是否包含关键字即可。灵活使用各种判断函数,才能使自动化测试用例更加健壮。

 

3.3.3 检测点设置中常见的错误

 

      在测试过程中,我们编写了测试用例,设置了检测点,可是在测试用例投入使用的过程中,我们不得不反复修改测试用例。因为测试用例总是通不过,维护成本很高。虽然这一部分是因为被测对象变化造成的,还有一部分原因是检测点设置的不对。所以常见的检测点设置中的错误如下:

 

(1)检测动态变化的元素

      检测点不能随着操作而变化,比如说翻页。我们想要测试翻页是否成功,就不能去检测第二页第一个元素是否是某个项目。因为如果项目增加的话,第二页第一个元素的项目可能会变化。应该先取一下第一个位置的项目名称,然后翻页,再判断现在第一个位置的项目是不是和刚刚获取的项目名称相同,如果不同,就证明翻页成功。

 

(2)遗漏检测点

      在一个测试用例中,我们要检测所有影响到的地方。如喜欢项目操作,如果我们只检测我的喜欢项目列表中有没有刚刚喜欢的项目,这是不够的。还要检测一下这个项目的喜欢数据是否+1,喜欢项目的入口是否变成已喜欢等相关检测点。

 

(3)检测点设置过多

      既然你说了,检测点是检测Bug的关键,我们就在每一步操作后添加检测点。这样做也是多余的,虽然检测点多了,更加安全一点儿,但是过多的检测点儿影响测试用例运行。而且测试用例如果出错了,我们去定位错误的时候,也非常困难,或是一个测试用例出错会导致相关的测试用例无法执行。

 

(4)忘记设置检测点或是检测点不是测试重点

      新手写自动化测试用例的时候,往往会写了每一步的测试操作代码,没有添加对应的检测点或是检测点设置不正确。明明是登录操作,操作完成之后却检测页面显示是否正确,这样会不管操作成功与否,测试用例都不会报错,使自动化测试用例失去了意义。

 

(5)检测需要刷新才有反映的元素

      在测试的时候,有些儿元素在操作完成后需要刷新一下页面才能显示出操作的结果。手工测试的时候,一般会触发刷新操作,可是自动化的时候,如果不刷新,就不符合预期结果。所以我们要添加刷新页面的代码,然后再去检测。

 

     这几种是常见的错误,当然也会有一些儿比较奇葩的检测点设置错误的情况。在此也不能一下列举了,遇到问题,要多尝试几种方法,会在网上搜索解决办法,这也是学习自动化测试必备的技能。 

 

八、第一个测试用例Hello World

   

      几乎所有编程语言的第一个程序就是输出Hello World,那我们也沿袭这个传统,第一个测试用例就是用百度搜索Hello World。

 

   首先我们先写一下这个测试用例的手工测试步骤:

 

(1)用浏览器打开百度首页。

(2)输入Hello World,然后单击“百度一下”按钮,进行查找。

(3)检测查找到的结果页面,第一项是否包含Hello World。

 

   这是我们手工测试的步骤,如果要转化成自动化测试用例,需要转化成我们需要的脚本语言编写的程序。

 

4.1.1 Selenium IDE录制

     

     如我们前面讲到的,可以利用Selenium IDE来录制测试步骤,然后添加上检测点,就可以形成一个测试用例。转化成我们需要的脚本语言格式,如python,然后保存文件,放到我们的开发环境下就可以调试运行了。

 

具体的录制方法如下:

 

(1)打开火狐浏览器,打开Selenium IDE,在IDE的Base URL中输入要录制的网站地址:http://www.baidu.com

 

(2)IDE默认是处于录制状态的,如果没有,单击红色按钮,录制。在火狐浏览器的地址栏中输入http://www.baidu.com,打开百度首页

 

(3)输入“Hello World”,单击“百度一下”按钮,进行搜索。

 

(4)在搜索结果页,右击第一个结果项,如图4.1.1.1所示,选择assert判断项,设置检测点。

图4.1.1.1 设置检测点

 

(5)单击Selenium IDE的回放按钮,检测录制的测试步骤,如图4.1.1.2所示,不过此时检测点会报错,原因是执行太快,页面没有刷新出来。

图4.1.1.2 回放录制的测试步骤

 

(6)为了解决这个问题,我们在检测点前添加一个等待。等待我们要检测的内容出现后,再去执行判断。如图:4.1.1.3所示,回放验证成功。

图4.1.1.3 添加等待命令

 

(7)现在说明我们录制的测试用例没有问题,导出录制的测试用例为python(webdriver)格式的,保存为helloworld.py.如图4.1.1.4所示:

图4.1.1.4 导出录制的测试用例

 

(8)检查导出的代码,Selenium IDE帮我们导出的代码如下:

 

# -*- coding: utf-8 -*-

from selenium import webdriver

from selenium.webdriver.common.by import By

from selenium.webdriver.common.keys import Keys

from selenium.webdriver.support.ui import Select

from selenium.common.exceptions import NoSuchElementException

from selenium.common.exceptions import NoAlertPresentException

import unittest, time, re

 

class Helloworld(unittest.TestCase):

    def setUp(self):

        self.driver = webdriver.Firefox()

        self.driver.implicitly_wait(30)

        self.base_url = "http://www.baidu.com/"

        self.verificationErrors = []

        self.accept_next_alert = True

   

    def test_helloworld(self):

        driver = self.driver

        driver.get(self.base_url + "/")

        driver.find_element_by_id("kw").clear()

        driver.find_element_by_id("kw").send_keys("Hello World")

        driver.find_element_by_id("su").click()

        for i in range(60):

            try:

                if u"hello world_百度百科" == driver.find_element_by_xpath("//div[@id='content_left']/div/h3/a").text: break

            except: pass

            time.sleep(1)

        else: self.fail("time out")

        self.assertEqual(u"hello world_百度百科", driver.find_element_by_link_text(u"hello world_百度百科").text)

 

 

    def is_element_present(self, how, what):

        try: self.driver.find_element(by=how, value=what)

        except NoSuchElementException, e: return False

        return True

 

    def is_alert_present(self):

        try: self.driver.switch_to_alert()

        except NoAlertPresentException, e: return False

        return True

 

 

    def close_alert_and_get_its_text(self):

        try:

            alert = self.driver.switch_to_alert()

            alert_text = alert.text

            if self.accept_next_alert:

                alert.accept()

            else:

                alert.dismiss()

            return alert_text

 

        finally: self.accept_next_alert = True

 

   

 

    def tearDown(self):

        self.driver.quit()

        self.assertEqual([], self.verificationErrors)

 

 

 

if __name__ == "__main__":

 

unittest.main()

代码讲解:

Ø  最前面是引用Webdriver相关的一些儿函数或方法。

Ø  创建一个测试类Helloworld,类里是具体的一些儿测试方法。

Ø  函数setUp,初始化火狐浏览器,要测试的网站URL等一些儿常用的变量。

Ø  函数test_helloworld() 是我们具体的操作步骤及验证点的检测。

Ø  函数is_element_present():判断元素是否在当前页面显示;is_alert_present():当前页面是否有浮层;close_alert_and_get_its_text():关闭浮层,并返回浮层标题。这几个函数由Selenium IDE自动生成,在本例是没有用到。

Ø  函数tearDown()关闭浏览器,判断是否有错误。

Ø  运行测试用例,这是python的功能,不做详解。

 

(9)将代码导入到开发环境中。打开Eclipse,新建PyDev工程如:WebAuto。将刚刚保存的helloworld.py文件导入到这个工程中,如图4.1.1.5所示:

图4.1.1.5导入保存的文件

 

(10)运行验证刚刚导入的代码,右击这个文件,“Run as”-->”python run”,查看运行结果。程序打开火狐,执行了测试用例,执行完成后关闭浏览器。如图4.1.1.6所示:

            图4.1.1.6 程序运行结果

 

(11)至此,利用Selenium IDE来录制测试用例,并且在开发环境下运行通过。可是我们发现这样录制测试用例还是存在问题的,转化后会有很多用不到的代码存在,而且不符合模块化编程的规范。所以我们还是喜欢自己编写测试用例,录制转化只能当作参考。

九、手动编写自动化测试用例

兼于用Selenium IDE录制转化测试用例会出现很多没有用的代码,并且代码复用性差,转化后的方法也不是最完美的,所以很多自动化高手是不会用这种方法来写自动化测试用例的。

 

      现在我们来讲解一下高手最常用的方法,自己编写自动化测试用例。当然编写之前也会有代码架构组织,公用函数编写,测试数据和测试用例代码的分离等工作要做。我们在本章就不涉及这些儿方面,只按一个普通的测试用例,以测试流程为序来编写测试用例,其他的内容将在后面的章节讲解。

 

   手工编写自动化测试用例的步骤,我们还以上面的Hello World为例:

 

Ø  打开Eclipse,创建pydev工程,为了方便起见,我们就用上面创建的WebAuto工程。

 

Ø  创建测试脚本文件:文件à新建àotheràPyDev&Module,然后在打开的对话框中输入 HelloWorld_demo,单击“fininsh”。最后在弹出的对话框中选择“Module:Unittest”。如图4.1.2.1所示:

图4.1.2.1新建文件unittest

 

 

 

Ø  此时会自动生成代码文件,内容如下:

 

'''

 

Created on 2015-3-4

@author: sxf

 

'''

import unittest

class Test(unittest.TestCase):

    def testName(self):

        pass

 

 

if __name__ == "__main__":

 

    #import sys;sys.argv = ['', 'Test.testName']

 

unittest.main()

 

  这是一个默认的文件内容,引用了unittest,创建Test类,测试方法testName,以及运行接口unittest.main().

 

Ø  我们需要在此基础上加上我们的测试用例,首先要修改类名为HelloWorld_Demo,测试函数为testSearch(注:测试函数必须以test开头,否则unittest将不识别。)然后开始加入我们的测试步骤及设置检测点。

 

Ø  测试用例代码及分析。

 

最后我们的测试用例代码如下:

 

# -*- coding: utf-8 -*-

 

'''

Created on 2015-3-4

@author: sxf

'''

 

import unittest

from selenium import webdriver

import time

 

class HelloWorld_Demo(unittest.TestCase):

 

    def setUp(self):

        self.driver = webdriver.Firefox()      

        self.base_url = "http://www.baidu.com/"

 

    def testSearch(self):

        '''

        Search Hello World!

        '''

        driver = self.driver

        driver.get(self.base_url + "/")

        driver.find_element_by_id("kw").clear()

        driver.find_element_by_id("kw").send_keys("Hello World")

        driver.find_element_by_id("su").click()

        time.sleep(3)

        #检查查询的结果

        self.assertEqual(u"hello world_百度百科", driver.find_element_by_xpath("//div[@id='content_left']/div/h3/a").text)

 

    def tearDown(self):

        self.driver.quit()

 

if __name__ == "__main__":

    #import sys;sys.argv = ['', 'Test.testName']

unittest.main()

 

代码讲解:

(1)首先我们要引入用例要用到的Webdriver,time.

(2)创建初始化函数setUp(),用于初始化火狐浏览器,及测试的baseURL.

(3)创建具体的测试函数testSearch(),将测试步骤及检测点添加进去。此处我们用的检测点是利用Xpath定位获取要检测的文本,然后和我们预期的相比较。其中的定位操作,还有测试步骤相对应的代码,我们可以从刚刚录制的代码中拷过来,也可以自己写,这样看你的编码水平了。

(4)创建测试用例清理函数tearDown(),关闭浏览器。

(5)这是一个测试用例最基本的结构,再复杂的测试用例,也是这样的结构,只不过测试步骤变多,检测点多些儿而已。

Ø  用Eclipse运行刚刚编写的测试代码,发现和Selenium IDE录制的结果一样。而我们的代码比录制转换后的代码简洁很多,这个才是我们想要的结果。

自动化测试代码结构

通常一个完整的自动化测试用例包含以下几部分:

(1)测试用例执行的先决条件。

     测试用例执行之前的公用变量的定义,或是测试用例执行之前的一些儿先决条件,如用户A和B要相互发私信操作时,必须相互关注等。而Python Unittest是用setUp()来处理的,因为所有测试用例执行前,先执行这个函数。

 

(2)具体的测试用例。

      根据不同的测试需要,来组织不同的测试用例。测试用例必须包含测试步骤,测试步骤执行完后对执行结果的检测。测试用例命名要以test开头,一个测试类中可以包含多个测试用例。

 

(3)测试用例执行完后的清理。

     测试用例执行完成后,如果对被测试对象产生了一些儿测试数据,则必须清除。如发布了一些儿文字,或是测试操作影响了两个测试账号间的关系等。如果不清除,则会影响下次测试用例的执行或是在并发过程中其他的测试用例的执行。

 

(4)测试用例的调用。

     在Python编写的自动化测试用例,可加上对测试用例的调用,否则测试用例将无法执行。

 测试用例编写过程中常见的问题

   

      在我们编写测试用例的过程中,会经常遇到一些儿问题的,这些儿问题影响着我们测试用例的质量。所以我们要在编写之前就在脑海里对它们提高警惕,避免这样的错误:

 

(1)随意命名测试用例类和函数名。

     这涉及到编码规范的问题,变量,函数,类的命名必须有意义,不可随意命名。在自动化测试用例中,不正规的命名,会影响测试用例的可读性,而且一旦执行出错,不便于定位问题。

 

(2)前提条件写到具体的测试用例中。

      setup()函数是每个测试用例执行之前都会调用的,所以这个函数里面写的是所有测试用例都要用到的前提条件。而有很多初学的同学,会把测试步骤都写到具体的测试函数中,这样就会造成把前提条件写了很多次,不符合代码重用机制。

 

(3)测试用例耦合度高。

      测试用例之间应该没有太多的耦合性,各自执行完测试用例,判断检测点之后,退出浏览器。这样不影响其他测试用例的执行,如果我们测试用例之间有耦合,可是使用相同的测试账号的话,单线程执行没有问题,多线程运行的时候,就会造成死锁或是相互影响。

 

(4)执行完测试用例,不对测试数据进行清理。

      执行完测试用例后,要对测试数据是行清理。而执行线上回归任务的自动化测试用例原则是不产生测试数据的。如果本次执行的测试数据不清理,下次就算执行失败了,检测执行结果的时候,如果检测到上次产生的测试数据了,也不会报错的。

 

(5)测试用例中没有注释。

      不管是什么样的语言写的程序,都要求有注释的。由于我们做自动化测试,大多没有经过详细的编码规范的培训,所有不喜欢写注释。可是如果不加注释,时间长了,你就不清楚这个测试用例是做什么的了,需要一步一步地去看代码分析,多费时啊!如果加上注释,只需要看一下注释即可。

 

十、常用页面元素自动化操作

 

5.1 输入类元素

 

      现在很多网站都实行会员制或是实名制的,所以注册和登录是非常常见的操作,在一个网站上输入各种信息也是必不可少的,我们首先讲解输入类元素。

 

5.1.1 input和textarea元素

      

      这两个是最常见的操作,这是的input的type为text和password类型,不是上传图片的,上图片我们下节再讲。对于这类输入文本的元素操作对于python是一种操作,先对元素进行定位,然后调用send_keys()函数,进行输入。

例:

def inputvalue(self,findby,elmethod,value):

        '''

        通过定制定位方法,在输入框中输入值

        @param findby: 定位方法,如:byid,byname,byclassname,byxpath等

        @param elmethod: 要定位元素的属性值 ,如:id,name,class name,xpath等

        @param value: 要给文本框输入的值

        '''

        if(findby == 'byid'):

            self.driver.find_element_by_id(elmethod).send_keys(value)

        elif(findby == 'byname'):

            self.driver. find_element_by_name(elmethod).send_keys(value)

        elif(findby =='byclassname'):

            self.driver.find_element_by_class_name(elmethod).send_keys(value)

        elif(findby == 'byxpath'):

            self.driver.find_element_by_xpath(elmethod).send_keys(value)

 

     这个inputvalue函数就是我对这类操作函数进行的封装,根据不同的定位类型,先对要输入的元素进行操作,然后send_keys(value)将关键字输入进去。

 

注:有些儿网站在输入框失去焦点后不会清除里面默认的字符,为了确保输入正确,我们在定位到元素后先调用clear()函数,将默认的字符清除后再进行输入操作。

 

5.1.2 input上传文件

     

     当input的type为file时,说明这个元素是上传文件的,这个时候我们的普通操作是,单击这个元素,然后在弹出的上传文件对话框中选择要上传的文件,最后是单击上传按钮。

 

      而在我们写自动化测试的时候,如果按这个步骤操作的话,会非常麻烦,因为我们无法定位弹出的上传文件对话框,要借助于第三方工具。其实没有必要这么麻烦,我们可以按照上面的上传文字的方法,不过参数不是文件 ,是文件路径,这样就能上传了。

例:

self. Driver.find_element_by_xpath (location).send_keys(filepath);

这个例子是用id来定位的,然后把文件路径作为参数传给这个元素。

 

注:这个文件路径最好是相对路径,将文件和代码放到一起,这样在代码放到其他的地方运行的时候,就不会出现找不到需要上传文件的现象了。

 

5.1.3 特殊按键的输入

 

    在输入过程中,有的时候我们需要输入特殊的按键,可是组合键。如按ESC或是CTRL+A等 ,这些儿我们无法用键盘输入的键,应该如何输入呢?

 

   其实和普通的字符输入差不多,不过需要调用特殊的类Key,例如:

(1)执行按ESC键操作

  self.driver.find_element_by_name ('image_file').send_keys(Keys.ESCAPE)

 

(2)执行按CTRL+a键操作

  self.driver.find_element_by_name ('image_file').send_keys((Keys.CONTROL, 'a'))

 

   当然对元素的输入操作这些儿是常见的,也有不常见的,如果遇到,可以酌情处理,多尝试几种方法。

 

5.2 单击类元素

   

      好像自从鼠标出现后,用鼠标完成的操作越来越多了,在我们自动化测试过程中,单击类操作是必不可少的操作之一。下面我们来看一下单击类操作的自动化测试代码:

 

5.2.1 按钮类元素单击

      在页面上单击按钮用来完成特定的操作,比较登录,注册,提交等。方法是,先定位到这个元素,然后调用click()函数。

 

例如:

def clickitem(self,findby,elmethod):

        '''

        通过定制定位方法,在对应的项目上执行单击操作

        @param findby: 定位方法,如:byid,byname,byclassname,byxpath等

        @param elmethod: 要定位元素的属性值 ,如:id,name,class name,xpath,text等

        '''

        if(findby == 'byid'):

            self.driver.find_element_by_id(elmethod).click()

        elif(findby == 'byname'):

            self.driver.find_element_by_name(elmethod).click()

        elif(findby == 'byxpath'):

            self.driver.find_element_by_xpath(elmethod).click()

        elif(findby == 'bytext'):

            self.driver.find_element_by_text(elmethod).click()

        elif(findby == 'byclassname'):

            self.driver.find_element_by_class_name(elmethod).click()

 

函数clickitem()通过各种定位方法,先将要定位的元素定位,然后执行click()操作。

 

5.2.2 超级链接单击操作

   

      在网站上单击超级链接,从而执行相应的操作。可以像按钮一样,先定位到这个超级链接,然后执行click()函数。但是针对超级链接,有专门的定位方法 :

      driver.find_element_by_link_text(link_text).click()

      driver.find_element_by_partial_link_text(link_text).click()

 

  将超级链接全部文字或是部分文字用来定位,然后调用click()函数,就可以完成单击操作。

 

5.2.3 鼠标右击和双击操作

 

     虽然在测试过程中,对被测试元素进行右击和双击操作不太常用,可是这两个操作还是很有用的。对于不太常用的操作,webdriver就没有将这个操作封装到Element类中,而是在ActionChains 

 

5.3 选择类元素

   

      在网站创建过一再要求操作要简单化,为了减少用户操作,就会提供很多选择类的操作,如超级链接类品牌选择,单选类操作,复选类操作,下拉菜单类选择操作等。这类操作有的是简单的单击一下,有的需要调用相应的函数,所以我们下面详细讲述一下。

 

5.3.1 超级链接类选择

      超级链接类选择往往出现在购物网站上,如京东,淘宝等。这类型的选择其实没有什么特殊的,可以采用上面提到的超级连接定位法,普通的定位,单击要选择的分类即可。

 

   此时注意,不同分类的选择,有可能显示结果的地方是新页面,或是iframe,此时要检测搜索的结果,就要先切换到新页面或是iframe当中。

 

5.3.2 单选框选择

     在填写信息的时候,经常会遇到性别选择,或是其他类型的单选按钮的选择。其实单选框如同普通元素,先对其进行定位,然后执行click()操作。

例如:

 

sexelem= driver.find_element_by_xpath(“sex”)

sexelem.click()

 

      执行了操作后,定位的单选按钮就处于选中状态了。如果不想选中 个单选按钮,可以单击其他的单选项,或是招待clear()函数,就取消选中。判断单选按钮是否处于选中状态,可以调用函数isSelected().

 

注:有的单选按钮的选择圆圈和显示文字可以分开定位,此时单击哪一个都可以,要考虑哪儿个方便定位。

 

5.3.3 复选框选择

  

      为了增加用户体验,给用户提供更多的选择,复选框的应用也是非常多的。复选框的使用是很简单的,定位到相应的复选框,然后单击。例如:

pricelem= driver.find_element_by_xpath(“price”)

pricelem.click()

      复选框的操作和单选框差不多,想取消选择,可以调用clear()函数,也可以再次单击就可以取消选择。判断是否选中,调用函数isSelected()。判断是否可用,调用函数isEnabled()。

 

5.3.4 下拉菜单类选择

      在填写信息的时候,城市的选择;可是对页面信息的选择,都会用到下拉菜单。在webdriver+python中,对应的是Select类,如:

from selenium.webdriver.support.ui import Select

      我们要操作下拉菜单,先用普通元素的定位方法,定位到这个元素,然后转化为select类型的。

         select = Select(self.driver.find_element_by_id(“selected”))

  接下来调用select_by_visible_text()函数来选择对应的菜单项。

 

例:select. select_by_visible_text(“北京”)

      在java版的webdriver还有其他的相应操作,不过python好像只有这一个操作。对于下拉菜单,还可以像普通元素一样,先单击下拉菜单 ,拉出菜单项,然后单击对应的选择项。不过这样操作时而好用,时而不好用,不建议用这种方法,此处只提供一种参考。

 

5.4 获取元素的文本

   

      在设置检测点的时候,我们经常需要获取操作后影响到页面元素,然后和预期的相比。所以此时用到最多的就是获取元素的文本,与预期的相比,相同则说明测试通过。

 

       获取元素文本的方法,不管你是div,link,或是其他的元素,都是一样的。先定位到这个元素,然后获取text属性。例如:

 

def gettext(self,findby,elmethod):

        '''

        通过定制定位方法,获取指定元素的文本

        @param findby: 定位方法,如:byid,byname,byxpath等

        @param elmethod: 要定位元素的属性值 ,如:id,name,xpath等

        @return: 返回获取到的元素文本

        '''

        if(findby == 'byid'):

               return self.driver.find_element_by_id(elmethod).text

        elif(findby == 'byname'):

              return self.driver.find_element_by_name(elmethod).text

        elif(findby == 'byxpath'):

              return self.driver.find_element_by_xpath(elmethod).text

        elif (findby=='byclassname'):

              return self.driver.find_element_by_class_name(elmethod).text

        elif (findby=='bycss'):

              return self.driver.find_element_by_css(elmethod).text

 

  gettext()函数通过各种定位方法,定位到要获取text的元素,然后将text返回。

 

5.5 页面或iframe切换

  

      在自动化测试过程中,难免会遇到,打开新页面或是切换到新的iframe中的情况。如果我们不将代码做相应的切换操作,将句柄切到新的页面或是iframe中,我们定位的时候,将出现找不到元素的情况。所以,在适当的时候切换一下句柄,然后再进行测试操作。

 

5.3.1 页面间的切换

     在网页中单击链接打开新网页,然后在新打开的页面中操作或是验证新页面中操作的结果等操作。如果我们用Selenium IDE录制脚本的时候,回放或是调试代码,执行到打开新页面后就会提示元素找不到。可是我们用Selenium IDE验证的时候,能找到要定位的元素,这是什么原因啊?

 

      其实就是当前的driver句柄在第一次打开页面的时候,取的是页面句柄,但是当我们打开新页面后,句柄还是原来的页面的。在原来的页面上查找新页面的元素,当然会找不到了。所以在我们验证新页面的元素的时候,需要先调用switch_to_window(0将句柄切换到新打开的页面。

 

例如:

    self.driver.switch_to_window(self.driver.window_handles[-1])

    self.driver.window_handles为获取所有打开窗口的句柄,-1为获取最后一个窗口的句柄,即最新打开的窗口的句柄。

 

5.3.2 iframe间的切换

     iframe间的切换在正常的页面中偶尔会遇到,如果要自动化测试后台相关的内容,则iframe是非常多的。几乎所有的操作都要在不同的iframe之间进行切换,本节我们只讲一种方法,更多的方法请参考:http://blog.sina.com.cn/s/blog_68f262210101mcxp.html

      例如现在页面上有两个iframe,一个name属性为“frame1”,另一个name属性为“frame2”,我们现在需要将句柄切换到frame2中:

   this.driver.switchTo().frame("frame2”);

   注:切换过iframe后,就可以在这个里面定位元素或是执行操作了。有的时候如果程序招待太快,可能会出现句柄切换不成功的现象,此时在切换句柄语句后,添加等待操作,然后再去查找就可以成功了。

十一、自动化测试实施

评审被测试对象功能

要先分析一下被测网站的功能,哪些儿是主要的,哪些儿必须自动化,哪些儿不能自动化。

自动化框架选择

selenium2.0(webdriver)

目前webdriver支持ie, chrome, firefox, opera等主流浏览器,其主要原因是这些浏览器实现了webdriver约定的各种接口。

十二、自动化测试用例运行环境

 

      由于我们采用的是python开发的脚本语言,对运行环境要求不是太高,可是相应的包还是要安装的。在脚本编写期间,我们一般是在自己机器上编写和调试的,运行环境是windows环境。在后期的交付运行,自动执行回归的时候,我们要放到服务器上,服务器是linux环境的。

 

      在Windows环境和linux环境下,python运行环境差别不大,所以不要太担心环境的问题。可是也有需要注意的地方,比如说文件路径的写法,两个环境下还是不同的。这也是我们一再要求用相对路径,最好用函数来获取路径,而不是把路径写死到代码中的原因。

自动化架构代码规划

代码规划的原因:

 

   (1)增加可读性。根据用途,将代码进行分类存放,方便团队其他成员进行代码管理与合作开发。

 

   (2)便于维护。自动化测试用例不可能是一成不变的,被测试的网站变化了,我们对应的自动化测试用例也要进行相应的维护。如果不进行规划,出现问题后不方便定位,更加会耗费大量的成本去维护。

 

  (3)提高代码利用率。结构化程序设计,要求我们对代码重复利用率要高,同样的代码要写在公用函数或是方便,减少代码量。

(1)为了增加代码的通用性,我们把大部分测试用例需要执行的操作步骤封装成函数,放到公共的类中,并把公共的类也按功能进行分类,统一放到一个文件夹下,如CommonFunction.

 

(2)将所有的测试用例放到一个文件夹下,测试用例与测试数据分离开,以便网站有变化的时候,我们只需要修改相应该的测试数据即可。测试用例放到一个文件夹下,如:TestCases。

 

(3)测试数据放到和测试用例同名的Xml文件中,然后通过公用的数据读取方法,对测试数据进行读取,然后在测试用例中调用通用的函数,读取到的数据传递过去。所有数据存放到统一的文件夹下,如:TestData.

 

(4)测试用例集的存放。由于不同的测试目的,我们会运行不同的测试用例。如果测试目的A,我们将运行测试用例1,2,3;测试目的B ,我们运行测试用例1,3,4,5。所以我们会有不同的测试用例集文件,将这些儿文件统一存放到一个文件夹下,如:TestSuites.

 

(5)其他的资源文件,可以创建不同的文件夹来进行存放,如图片文件夹image.

 

   所以,经过规划后,我们的测试用例结构如图6.5.2所示,图中的文件是我先前写的测试用例。下面的章节,我们会具体讲述测试用例:

 

图6.5.2 自动化测试用例代码结构规划

十三、编写自动化用例 

我们规划好了代码架构,就可以编写具体的测试用例了。首先, 我们写登录的测试用例,在写自动化测试用例的时候,我们要先写一 下 公用函数 类。 根据 需要, 我 们写了三 个通用的 类放到CommonFunction  文件夹下:WebDriverHelp  用来存放所有页面操作用到公用方法;QT_Operations用来存放具体操作功能块,如登录,退出等;DataOperations用来存放所有数据操作,用来读取 xml中的测试数据。

然后我 们在  TestCases  文 件夹 下编 写登录 的测 试用 例 TestCase_QT_Login.py  执行具体的测试操作,验证测试用例执行是否成功。

并把测试用例需要的测试数据, 放到 TestData 文件夹下

 

TestCase_QT_Login.xml 文件中。如果网站有所变化,可以修改这个里面的测试数据,从而减少代码维护的成本。

 

6.6.1   WebDriverHelp类的内容

 

WebDriverHelp是我们所有测试用例能用到的方法,可以在编写测试过程中不断抽象出来,写到这个类里面,相当于对 Webdriver 再次做了一下封装。

下面是部分代码,以供大家参考:

@author:songxianfeng@copyright: V1.0

'''

import time importdatetime

from selenium import webdriver

from selenium.webdriver.support.ui import Select

 

from selenium.common.exceptions importNoSuchElementExceptionfrom selenium.webdriver.common.action_chainsimportActionChains fromselenium.webdriver.common.keys import Keys

global G_WEBDRIVER, G_BROWSERTYTPE,DRIVER

 

class WebDriverHelp(object):

'''

本类主要完成页面的基本操作,如打开指定的URL,对页面上在元素进行操作等

'''

 

def init (self,btype="close" ,atype="firefox",ctype="local"):

'''

根据用户定制,打开对应的浏览器

@param bType: 开关参数,如果为close则关闭浏览器

@paramaType:打开浏览器的类型,如chrome,firefox,ie等要测试的浏览器类型@paramcType:打开本地或是远程浏览器:local,本地;notlocal:远程                                                              ''' globalDRIVER

if( btype == "open" ):

if( atype == "chrome" ):if(ctype == "local" ):

DRIVER =webdriver.Chrome()

 

DRIVER.maximize_window() elif(ctype == "notlocal"):

DRIVER =webdriver.Remote(command_executor='http://124.65.151.158:4444/wd/hub',desired_capabilities=webdriver.DesiredCapabilities.CHROME)

DRIVER.maximize_window() elif( atype == "ie" ):

if(ctype == "local"):

DRIVER = webdriver.Ie()DRIVER.maximize_window()

elif(ctype =="notlocal"):DRIVER =

webdriver.Remote(command_executor='http://124.65.151.158:4444/wd/hub',desired_capabilities=webdriver.DesiredCapabilities.INTERNETEXPLORER)

DRIVER.maximize_window()

elif( atype == "firefox"): if(ctype == "local" ):

DRIVER = webdriver.Firefox() DRIVER.maximize_window()

elif(ctype == "notlocal"):

DRIVER =

webdriver.Remote(command_executor='http://10.20.5.56:4444/wd/hub',desired_capabilities=webdriver.DesiredCapabilities.FIREFOX)

DRIVER.maximize_window()

 

self.DRIVER = DRIVER

 

 

def setup(self,logintype):

'''

定制测试URL

@param loginplace: 指定测试的URL: qiantai:前台测试地址,houtai:后台测试地址,zhengshi:正式环境测试地址

ysh:原始会测试地址zhengshiysh:正式原始会测试地址'''

try:

qiantai_url = "http://test.zhongchou.cn"

ysh_url ="http://test.ysh.zhongchou.cn"houtai_url ="http://test.admin.zhongchou.cn"zhengshi_url ="http://www.zhongchou.cn"zhengshi_ysh_url ="http://ysh.zhongchou.cn"

 

if(logintype=="qiantai"):

self.DRIVER.get(qiantai_url)elif(logintype=="houtai"):

self.DRIVER.get(houtai_url)

 

elif(logintype=="zhengshi"):

self.DRIVER.get(zhengshi_url)elif(logintype=="ysh"):

self.DRIVER.get(ysh_url)

elif(logintype=="zhengshiysh"):

self.DRIVER.get(zhengshi_ysh_url)

else:

print '路径错误!'

self.DRIVER.implicitly_wait(1exceptNoSuchElementException:

print '您选择的测试地址出错!!'

def teardown(self):

'''

关闭浏览器

'''

self.DRIVER.quit()

 

 

def geturl(self,url):

'''

打开指定的网址

@param url: 要打开的网址

'''

self.DRIVER.get(url)

def selectvalue(self,findby,select,selectvalue):

'''

通过定制定位方法和要选择项的文本,选择指定的项目@paramfindby:定位方法,如:byid,byname,byclassname@paramselect: 要执行选择操作的下拉框句柄

@paramselectvalue: 下拉框中要选择项的文本

'''

if(findby == 'byid'):

select = Select(self.findelementbyid(select))elif(findby =='byname'):

select = Select(self.findelementbyname(select))

elif(findby =='byclassname'):

select=Select(self.findelementbyclassname(select))select.select_by_visible_text(selectvalue)

 

def   inputvalue(self,findby,elmethod,value):

'''

通过定制定位方法,在输入框中输入值

@param findby: 定位方法,如:byid,byname,byclassname,byxpath@param elmethod: 要定位元素的属性值 ,如:id,name,class name,xpath@param value: 要给文本框输入的值

 

'''

if(findby == 'byid'):

self.findelementbyid(elmethod).send_keys(value)elif(findby == 'byname'):

self.findelementbyname(elmethod).send_keys(value)elif(findby =='byclassname'):

self.findelementbyclassname(elmethod).send_keys(value)elif(findby == 'byxpath'):

self.findelementbyxpath(elmethod).send_keys(value)

……

上面的代码都有很详细的注释,在此就不一一讲述了。

 

6.6.2   QT_Operations类的内容

 

QT_Operations 类是业务相关的公用功能块的封装,以便增加函数的公用性,减少代码量。例如,登录,在很多测试用例的第一步都需要先登录再操作的。所以你可以抽像出测试用例中的功能模块,封装后放到这个类中。

QT_Operations 类的部分代码展示:

#-*- coding: UTF-8 -*-

'''

Createdon2014-12-15@author:songxianfeng@copyright: V1.0

'''

importtimeimport win32apiimportwin32con

from WebDriverHelpimport WebDriverHelpclassQT_Operations(object):

'''

众筹前台相关操作'''

def login(self,userName,passwd):

'''

从首页直接登录

 

@paramuserName:用户名@param passwd:密码

@param type1:指示登录方式,1为从主页登录,2,从登录页登录'''

WebDriverHelp().clickitem("byclassname""Js-showLogin") time.sleep(3)WebDriverHelp().clearvalue('byname','username') WebDriverHelp().inputvalue('byname','username',userName) WebDriverHelp().clearvalue('byname','user_pwd') WebDriverHelp().inputvalue('byname','user_pwd',passwd) time.sleep(1)

WebDriverHelp().clickitem("byclassname""a-btn") time.sleep(5)

 

def logout(self):

'''

退出登录'''

WebDriverHelp().geturl("http://www.zhongchou.cn/usernew-loginout")

……

 

展示部分只包含了登录和退出功能,其他的功能可以根据测试用例的需要进行添加。

 

6.6.3  DataOperations类的内容

DataOperations 类是对测试数据进行读取的操作,我们是用xml 来存放测试数据的,所以测试用例执行的时候,需要先将测试数据读取出来,传递给相应的函数来对测试用例进行执行。然后根据执行的结果,判断测试用例是否执行成功。

DataOperations 的内容:

#-*- coding: UTF-8 -*-

'''

Created on 2014-12-15@author:songxianfeng@copyright: V1.0

'''

import MySQLdb

from xml.dom import minidom

 

global DOC,CONN

 

 

class DataOperations(object):

'''

数据读取相关操作

'''

 

 

def init (self,filename):

'''

初始化xml文档

'''

global DOC,CONN

DOC = minidom.parse("../testData/" +filename)

 

def readxml(self,ftagname,num,stagname):

'''

从指定的文件中中读取指定节点的值

@param ftagname:起始节点的名称,如:project@param num:取与起始节点相同的第num个节点@param stagname: 起始节点下的二级节点@return: 返回二级节点的值

'''

root = DOC.documentElementmessage=root.getElementsByTagName(ftagname)[num]

return message.getElementsByTagName(stagname)[0].childNodes[0].nodeValue

 

 

def readxml_attribute(self,ftagname,num,stagname,attributeName):

'''

all_case.xml文件中读取节点的属性值@param ftagname:起始节点的名称,如:project @param num:取与起始节点相同的第num个节点@param stagname:起始节点下的二级节点@paramattributeName: 二级节点的属性名@return:返回二级节点指定的属性值

'''

 

 

root = DOC.documentElementmessage=root.getElementsByTagName(ftagname)[num]

return message.getElementsByTagName(stagname)[0].getAttribute(attributeName)

 

 

python 对 xml 的读取操作,如果你不太明白,可以去自行学习相关的内容,要教程不讲解相关的操作。

 

6.6.4      具体的测试用例

 

上面的公用方法类创建以后,我们就可以着手编写具体的测试用例了。在TestCases 文件夹下创建测试用例 TestCase_QT_Login.py,然后编写下面的测试步骤:

(1)    打开众筹网。

(2)     点击登录按钮,输入用户名和密码。

(3)    验证是否登录成功,用户昵称是不是刚刚登录的账号。

(4)    退出登录,关闭浏览器。测试用例代码如下:

-*- coding: UTF-8 -*-

'''

Createdon2014-12-15@author:songxianfeng@version: v1.0

'''

import unittest import time

#导入需要的公共函数类

from CommonFunction.WebDriverHelpimport WebDriverHelpfromCommonFunction.DataOperations import DataOperations

from CommonFunction.QT_Operationsimport QT_Operationsclasstestcases_login(unittest.TestCase):

'''登录检测'''

def setUp(self):

WebDriverHelp("open","firefox","local").setup("zhengshi")#打开浏览器,并打开众筹网

 

def testlogin(self): #登录检测

dataoper=DataOperations("TestCase_QT_Login.xml") #读取测试数据#登录

QT_Operations().login(dataoper.readxml('login'0,'username'),

dataoper.readxml('login'0,'password'))

self.assertEqual(WebDriverHelp().gettext('byxpath',dataoper.readxml('login',0,'checkpoint1')),dataoper.readxml('login'0'value1')) #判断登录是否成功#退出

QT_Operations().lgut() time.sleep(5)

self.assertEqual(WebDriverHelp().gettext('byclassname',dataoper.readxml('login'0,

'checkpoint2')),dataoper.readxml('login'0'value2')) #判断退出是否成功

 

def tearDown(self):

WebDriverHelp().teardown()#关闭浏览器

     

        if   name=="main ": 

        unittest.main()

  

经过我们上面的封装,现在具体的测试用例只是传参数,调用具体的函数,验证执行结果。是不是非常简单?有点儿像我们小时候玩积木,用一块块现成的积木堆积出魔幻的城堡。

6.6.5     测试用例的具体数据

由于我们把测试用例和测试数据完全分离开了,所以我们用和测试用例同名的文件名命名对应的测试数据文件。登录测试用例的数据文件是 TestCase_QT_Login.xml,具体内容如下:

<?xml version="1.0"encoding="UTF-8"?>

<TestData>

<login name="登录测试数据">

<username>183*****905</username>

<password>*******</password>

<checkpoint1>//div[@id='Js-header-loginBtn']/span/i[2]</checkpoint1>

<value1>潜龙0318</value1>

<checkpoint2>Js-showLogin</checkpoint2>

<value2>登录</value2>

</login>

</TestData>

 

我们将要验证的数据,获取验证元素的 Xpath 都写到这个里面, 这样就算网页有所变化,我们只需要改这个数据文件中对应的Xpath即可,不需要更改测试用例。这样可以将网站变化影响到测试用例降到最低,同时也减少了我们维护测试用例的成本。编写完上面所有的代码后,我们只要右击测试用例,选择 Run  as->python run,调试运行测试用例即可。

十四、TestSuite组织测试用例

      平时我们编写测试用例的时候,都是继承unittest.TestCases类来编写测试用例的,重写了setUp(),tearDown()方法,并且定义以'test'开头的具体方法,来组织成一个个测试用例。而很多的测试用例文件,我们可以用unittest.TextTestRunner()来组织运行测试用例。而根据不同的测试需要,来编写不同的suite文件。

 

例如:我编写的TestSuite_Online_All.py文件:

 

# -*- coding: utf-8 -*-

'''

Created on 2014-6-12

@author: songxianfeng

'''

import unittest

import sys

import os

sys.path.append("..")

sys.path.append(os.getcwd()+"/src/")

 

#引用测试用例文件

from TestCases.TestCase_QT_Login import testcases_login

from TestCases.TestCase_QT_Index import testcases_index

 

class testsuit_online_all():

    def test(self):

        if __name__ == "__main__":

            #1,登录检测: testlogin

            #2,首页检测: testindex

            #......      

            #构造测试集             

            suite = unittest.TestSuite() 

            suite.addTest(testcases_login('testlogin'))

            suite.addTest(testcases_index ('testindex'))

 

            # 运行测试用例集 

            runner = unittest.TextTestRunner() 

            runner.run(suite)  

if __name__ == "__main__":   

        testsuit_online_all().test()  

 

        先引用测试用例文件中的测试类,如:testcases_index,然后利用“测试类(测试函数)”的方法,将具体的测试函数添加suite中,然后利用unittest.TextTestRunner()的run()函数来运行测试用例集中的测试用例。

 

测试用例的运行

 

     通过testsuite将需要的测试用例组织起来后,当需要执行这一系列的测试用例的时候,只需要执行python TestSuite_Online_All.py 命令即可。或是右击TestSuite_Online_All.py文件,选择“Run As”—>”python run”运行测试集文件即可。

       为了方便管理,我们将所有的测试用例集文件放在TestSuites文件夹下,在以后配置Jenkins自动运行Job的时候就可以根据需要,进行不同的配置。 

十五、利用Jenkins来管理自动化测试用例

 

     Jenkins是基于Java开发的一种持续集成工具,用于监控持续重复的工作,功能包括:

 

(1)持续的软件版本发布/测试项目。

(2)监控外部调用执行的工作。

 

      由于其是开源的,所以现在很多公司都用它来管理代码,当然要做到持续集成还是有很多工作要做的,我们只用它来调用我们的自动化测试用例。

 

Jenkins基本配置

 

    Jenkins这个开源工具的安装及配置管理,在网上有很多相关的教程,如:http://blog.csdn.net/wangmuming/article/details/22925127

这个上面讲的就很详细,所以我们不在此详细讲述相关的操作。本节我们只讲解,如何把我们的自动化测试用例配置到jenkins上。

 

   下面我们以一个实例来讲解:

(1)我们编写了测试用例文件以及suite文件,并将所有的文件放到SVN:svn://svn.corp.ncfgroup.com/selenium_test/yyzhongchou下面。

(2)我们在要运行测试用例的服务器上安装并配置好了jenkins,这个配置你可以在网上查找相关的方法自行安装配置。

(3)新建一个job ,命名为Zhongchou-web-test-testsuit,然后打开这个job,单击配置菜单。

(4)给我们这个Job添加描述,允许执行项目的人员“启动安全项目”,如图7.2.1所示:

图7.2.1 添加描述及启动项目安全

 

(5)对我们测试用例的源码进行管理,根据我们源码管理的工具不同,选择不同的方法。我们放的是SVN,所以选择Subversion项,然后在后面填写我们的SVN地址,如图7.2.2所示:

图7.2.2 源码管理

 

(6)添加构建命令。当我们执行Job的时候,怎么运行我们的测试用例呢,在这一步中,我们要添加上执行我们测试用例的命令:

 

python .\src\testSuit\testSuit_zhongchou_all.py,这样运行的时候就会调用testsuite,执行测试集中的所有测试用例了,如图7.2.3所示:

图7.2.3 添加构建命令

 

(7)构建Job。填写完成之后,点击保存按钮,返回job页。当我们想执行测试用例的时候,点击页面左侧的“立即构建”,即可运行测试用例。如图7.2.4所示:

图7.2.4 构建Job

 

(8)查看执行结果。要想查看测试用例执行的结果,我们可以单击左侧的“Build History”下面的构建项目,在打开的页面中单击左侧的“控制台输出”,就能看出用例执行的结果了。这样就可以定位错误,进行调试。如图7.2.5所示:

图7.2.5查看控制台输出

经过上面的配置,我们已实现了把自动化测试用例接入到jenkins中,虽然比手工执行高端一点儿,但这不是我们想要的结果。我们想要自动化执行测试用例,监控执行结果,如果出错给我们发邮件或是短信,这样我们才能及时处理。所以我们要进一步去配置或是优化测试用例。

 

7.3.1 自动化执行测试用例

      Jenkins是用来管理和配置持续化集成的,在持续化集成中,自动运行脚本语言是最基本的功能。下面我们就配置一下:

 

(1)定时执行测试用例

 

如图7.3.1.1所示,选择构建触发器中选择build periodically,配置执行的方法:

图7.3.1.1配置定时执行

 

选择 Build periodically,在 Schedule 中填写 0 * * * *。

 

第一个参数代表的是分钟 minute,取值 0~59;

 

第二个参数代表的是小时 hour,取值 0~23;

 

第三个参数代表的是天 day,取值 1~31;

 

第四个参数代表的是月 month,取值 1~12;

 

最后一个参数代表的是星期 week,取值 0~7,0 和 7 都是表示星期天。

 

所以 0 * * * * 表示的就是每个小时的第 0 分钟执行一次构建。

 

(2)触发式执行测试用例

 

如图7.3.1.2所示,选择构建触发器中选择“在其他项目完成后构建”或是“触发无私构建”,然后写上触发的项目了。如在开发上传完代码,完成构建后,自动触发回归测试自动用例来进行回归测试。

图7.3.1.2 触发式构建

 

7.3.2 程序执行失败邮件通知

       当测试用例实现自动化执行后,我们需要知道执行的结果。一般测试用例执行成功后,我们并不太关心。但是如果执行失败了,我们需要知道为什么失败,是被测试对象存在bug,还是我们的自动化测试代码有问题了?然后去排查,找出问题所在,这也是自动化测试的意义。

 

       而用例执行失败后发邮件通知,这个功能是jenkins自带的功能,我们只需要对其进行如下配置即可。

 

(1)打开要进行配置的job, 单击“配置”项。

 

(2)在“构建后操作”下单击“Add post build actions”,然后选择“E­-mail Notification”项。

 

(3)然后在Recipients后面的框中填写要接收错误报告的邮箱地址,以空格分隔多个地址。如图7.3.2.1所示:

图7.3.2.1 填写接收报告邮件地址

 

(4)在下面勾选“每次不稳定的构建都发送邮件通知 ”复选框,然后单击保存,这样在测试用例执行失败或者job构建失败后就会发邮件给所填写的邮件地址了。 

 

7.3.3 测试执行失败短信通知

      现在手机使用这么发达,邮件通知感觉到不那么及时了,如果不时常查看一下 邮箱,即使是Jenkins给我们发了邮件我们也不能及时收到。所以如果自动化测试用例执行失败了,能发送短信,这不是很好吗?

 

      遗憾的是,Jenkins没有这个功能,如果想实现这个目标,我们只有自己努力了!下面我们分析一下思路:

 

(1)   我们要根据执行结果来分析出测试用例执行成功了或是失败了,这个虽然Jenkins会自己分析,可是我们没有办法获取它分析的结果。所以我们要保存执行结果。

 

(2)   解析保存的执行结果,如果失败了,解析出哪些儿测试用例失败了,把测试用例名字保存下来,以便作为我们失败通知短信的内容。

 

(3)   需要一个发短信给固定手机的方法,我的办法是我们公司有一个公共短信平台,申请了相关的权限后就可以直接调用发短信接口向任何手机号发短信。读者要想达到这个目的,请自行想办法,因为没有免费的短信接口。

 

(4)   上面三方面我们需要写一个脚本来做这些儿事情,我们暂时命名为TestGetResult.php,因为调用接口php最方便。脚本都是在linux下执行的,所有python,php都不会相互影响的。脚本内容涉及公司接口,就不给大家展示了。

 

(5)   如果测试用例执行成功,则直接执行Jenkins返回成功,如果失败,则调用此脚本发送短信,并同时调用Jenkins发送邮件。所以我们的脚本执行不能影响Jenkins对执行结果的判断。

 

(6)   为了达到这个目的,我们需要在“构建”—>“Excute Shell”下添加脚本语言,如下所示:

 

01  #!/bin/sh

02  python .\src\testSuit\testSuit_zhongchou_all.py >./Result/WebResult.log

03  if [ $? -ne 0 ];

04  then

05  php TestGetResult.php

06  exit 1

07  else

08  exit 0

09  fi

 

脚本讲解:

 

A,第02行我们是调用执行suite文件,执行测试用例,并将结果保存到./Result/WebResult.log文件中。

 

B,第03行判断第一行执行的结果,如果执行结果不等于0,说明测试用例执行失败,然后调用05行我们处理测试结果,发短信的脚本。

 

C,第06行很关键,当测试用例执行失败后,第02行会返回一个非0的结果,此时我们调用05行执行。05行执行成功后会返回0,此时jenkins接到的结果代码是0,会把执行结果置成成功,并且不会发邮件。所以06行,我们人为的返回一个非零的代码给Jenkins,为了不影响Jenkins的结果。

 

  D,第08行和06行的目的是一样的,当03行判断结果为失败时,返回代码是非零的,如果不在08行添加一个人为地返回0的语句,测试用例执行成功时,Jenkins根据返回码也会认为是失败。为了不影响Jenkins原来的判断结果,我们添加了06和08两个强制返回语句。

 

   至此,我们完成了Jenkins的配置,这些儿配置可以满足我们对自动化测试用例的失败监控。当然,如果你们有其他的需要,可以去网上学习Jenkins的其他配置及插件的使用,学无止境嘛!

十六、自动化测试用例报告

     

        Jenkins可以随时监控自动化测试用例的执行,如果有错误就会及时通知我们。如果我们想向我们的领导展示一下我们自动化的成果,这时一个漂亮的执行报告就是非常必要的了。虽然Python不能生成像testng那样漂亮的报告,不过也是可以生成清晰的报告的。

 

   Python+Webdriver生成报告的方法如下:

 

(1)下载HTMLTestRunner.py文件:地址http://tungwaiyip.info/software/HTMLTestRunner.html

 

(2)将该文件保存在python安装路径下的lib文件夹中。在文件中能import HTMLTestRunner成功,即配置成功。

 

注:如果失败,在项目中新建一个这样的文件也是可以的,只要达到能引入和使用就行。

 

(3)修改TestSuite文件,添加生成测试报告的语句,如下所示:

 

# -*- coding: utf-8 -*-

 

'''

Created on 2014-6-12

@author: songxianfeng

'''

import unittest

import sys

import os

sys.path.append("..")

sys.path.append(os.getcwd()+"/src/")

#引用测试用例文件

from TestCases.TestCase_QT_Login import testcases_login

from TestCases.TestCase_QT_Index import testcases_index

class testsuit_online_all():

 

    def test(self):

        if __name__ == "__main__":

            #1,登录检测: testlogin

            #2,首页检测: testindex

            #......      

            #构造测试集             

            suite = unittest.TestSuite() 

            suite.addTest(testcases_login('testlogin'))

            suite.addTest(testcases_index ('testindex'))

 

            # 运行测试用例集 

 

            filename="./Reoport/TestReport.html"#测试报告路径

fp=file(filename,'wb')

runner=HTMLTestRunner.HTMLTestRunner(stream=fp,title='Result',description='Test_Report')#添加测试报告

 

            runner.run(suite)  

 

if __name__ == "__main__":   

        testsuit_online_all().test()

 

(4)当执行完测试用例后,去打开./Report/TestReport.html文件,就可以看到,类似图7.4.1样式的报告。现在你就可以将此报告发给你们老大,以数据形式展示你的成绩了。

图7.4.1 测试报告