本文转自:https://blog.csdn.net/TestingGDR/article/details/81950593css
写在最前面:目前自动化测试并不属于新鲜的事物,或者说自动化测试的各类方法论已经层出不穷,可是,可以在项目中锲而不舍的实践自动化测试的团队,却依旧不是很是多。有的团队知道怎么作,作的还不够好;有的团队还正在探索和摸索怎么作,甚至还有一些多方面的技术上和非技术上的旧系统须要重构……html
本文将会从使用和实践两个视角,尝试对基于Web UI自动化测试作细致的分析和解读,给各位去思考和实践作一点引路,以便各团队能找到更好的方式。前端
1. 使用测试工具
《论语》有云:工欲善其事,必先利其器。在开始具体的自动化测试以前,咱们须要作好更多的准备,包括如下几个方面:node
认识自动化测试
准备自动化测试工具
使用有效的方式
针对具体的测试对象
接下来的第一部份内容,咱们将会从上述的几个方面进行探讨。python
1.1 自动化测试理论介绍
自动化测试的5Wmysql
正如开篇所提到的,自动化测试再也不是一个陌生的话题,而是一个具体的存在。做为测试实践活动的一部分,咱们首先分析一下自动化测试的方方面面。git
WHAT, 什么是自动化测试github
G.J.Myers在其经典的著做《软件测试艺术》(The Art of Software Testing)一书中,给出了测试的定义:web
“程序测试是为了发现错误而执行的过程。”sql
这个概念产生于30年前,对软件测试的认识还很是有局限性,固然也是由于受瀑布开发模型的影响,认为软件测试是编程以后的一个阶段。只有等待代码开发出来之后,经过执行程序,像用户那样操做软件去发现问题。
自动化测试:以人为驱动的测试行为转化为机器执行的一种过程
自动化测试,就是把手工进行的测试过程,转变成机器自动执行的测试过程。该过程,依旧是为了发现错误而执行。所以自动化测试的关键在于“自动化”三个字。自动化测试的内容,也就相应的转变成如何“自动化”去实现本来手工进行的测试的过程。
全部的“自动化”,依靠的无疑都是程序。
经过程序,能够把手工测试,转变成自动化测试。
WHEN, 在何时开展自动化测试
自动化测试的开展,依赖于“程序”。那么程序,其实就是由“源代码”构建而来的。那么原则上,只要能作出自动化测试所须要的“程序”的时候,变能够进行自动化测试。但每每,并非全部的“时候”都是好的“时机”。从这个W开始,咱们将会加入对于成本的顾虑,也正是由于“成本”的存在,才使得下面的讨论,变得有意义。
全部的开销,都是有成本的。构建成“程序”的源代码,也是由工程师写出来的。那么须要考虑这个过程当中的成本。基于这个考虑,在可以比较稳定的构建“程序”的时候,不须要花费太多开销在“源代码”的时候,就是开展自动化测试的好时机。这个开销包括编写和修改源代码,而源代码指的是构建出用来作自动化测试的程序的源代码。
WHERE, 在什么地方进行自动化测试
自动化测试的执行,依靠的是机器。那么自动化测试必将在“机器”上进行。通常来讲,这个机器包括桌面电脑和服务器。经过将写好的源代码部署在机器上,构建出用来作自动化测试的"程序",而且运行该程序,实现自动化测试。
WHICH, 对什么目标进行自动化测试
自动化测试的目标,是被测试的软件。抛开人工智能的成分,手工测试必将在“人工智能”足够普及和足够“智能”以前,替代一大部分不须要“人类智能”的手工测试;以及自动化测试会作一些手工测试没法实施的,或者手工测试没法覆盖的测试。
不须要“人类智能”的普通手工测试
界面的普通操做
经过固定输入和固定操做而进行的流程化测试
重复的普通测试
手工测试没法实施或者覆盖的
大量的数据的输入
大量的步骤的操做
源代码基本的测试
系统模块间接口的调用测试
……
在这里向你们推荐一个学习交流群:672899761
HOW, 如何开展自动化测试
准备测试用例
找到合适的自动化测试工具
用准确的编程造成测试脚本
在测试脚本中对目标进行“检查”,即作断言
记录测试日志,生成测试结果
和全部的其余测试同样,自动化测试的流程也是由“用例”执行和“缺陷”验证组成。差异是须要找到合适的“工具”来替代“人手”。不一样目标的自动化测试有不一样的测试工具,可是任何工具都无不例外的须要“编程”的过程,实现“源代码”,也能够称之为测试脚本。因而开展自动化测试的方式基本上以下:
自动化测试的典型金字塔原理
谈到自动化测试,就不得不提的一我的和概念就是:Martin Fowler和他的金字塔原理。首先请看金字塔原理的图示以下:
该图说明了三个问题:
自动化测试包括三个方面:UI前端界面,Service服务契约和Unit底层单元
越是底层的测试,运行速度越快,时间开销越少,金钱开销越少
越是顶层的测试,运行速度越慢,时间开销越多,金钱开销越多
这是理想中的金字塔原理。
在实际的项目中,尤为是结合国内的项目实践,其实还隐藏了另外一个问题:越是顶层的测试,效果越明显。有句话说“贵的东西,除了贵,其余都是好的!”可以很清晰的阐述这个观点。
金字塔原理在国内的适应性也有必定的问题
自动化测试的起步不是特别早
甚至软件测试很长一段时间都在进行基于业务的手工测试,测试人员的代码能力相对较弱
开发人员在代码中不太习惯写单元测试
近些年基于服务契约的API测试也在兴起
相对来讲,在基于UI前端界面的自动化测试反却是开展和实施的不是特别多。尽管基于界面的测试带来的效果仍是可以立竿见影的。对于产品的质量提高,仍是比较容易有保证。
自动化测试的适用范围
自动化测试能够涉及和试用的范围主要在如下方面:
基于Web UI的浏览器应用的界面测试
基于WebService或者WebAPI的服务契约测试
基于WCF、.net remoting、Spring等框架的服务的集成测试
基于APP UI的移动应用界面测试
基于Java、C#等编程文件进行的单元测试
本文集中讨论第一条:基于Web UI的浏览器应用的界面测试。界面的改动对于测试来讲,具备较大的成本风险。主要考虑如下方面:
任务测试明确,不会频繁变更
每日构建后的测试验证
比较频繁的回归测试
软件系统界面稳定,变更少
须要在多平台上运行的相同测试案例、组合遍历型的测试、大量的重复任务
软件维护周期长
项目进度压力不太大
被测软件系统开发比较规范,可以保证系统的可测试性
具有大量的自动化测试平台
测试人员具有较强的编程能力
自动化测试的流程
自动化测试和普通的手工测试遵循的测试流程,与项目的具体实践相关。通常来讲,也是须要从测试计划开始涉及自动化测试的。
测试计划:划定自动化测试的范围包含哪些需求,涉及到哪些测试过程
测试策略:肯定自动化测试的工具、编程方案、代码管理、测试重点
测试设计:使用测试设计方法对被测试的需求进行设计,得出测试的测试点、用例思惟导图等
测试实施:根据测试设计进行用例编写,而且将测试用例用编程的方式实现测试脚本
测试执行:执行测试用例,运行测试脚本,生成测试结果
1.2 自动化测试工具
基于Web UI的自动化测试工具主要有两大类:付费的商业版工具和无偿使用的开源版工具。典型的有两种:
UFT,QTP被惠普收购之后的新名称。
经过程序的录制,能够实现测试的编辑
录制的测试脚本是 VBScript 语法
成熟版的商业付费工具
工具比较庞大,对具体的项目定制测试有难度
SELENIUM,本次选择的开源工具
自己不是测试工具,只是模拟浏览器操做的工具
背后有 Google 维护源代码
支持所有主流的浏览器
支持主流的编程语言,包括:Java、Python、C#、PHP、Ruby、JavaScript等
工具很小,能够实现对测试项目的定制测试方案
基于标准的 WebDriver 语法规范
1.2.1 Selenium 基本介绍
Selenium`是开源的自动化测试工具,它主要是用于Web 应用程序的自动化测试,不仅局限于此,同时支持全部基于web 的管理任务自动化。
Selenium官网的介绍
Selenium is a suite of tools to automate web browsers across many platforms.
runs in many browsers and operating systems
can be controlled by many programming languages and testing frameworks.
Selenium 官网:http://seleniumhq.org/
Selenium Github 主页:https://github.com/SeleniumHQ/selenium
Selenium 是用于测试 Web 应用程序用户界面 (UI) 的经常使用框架。它是一款用于运行端到端功能测试的超强工具。您可使用多个编程语言编写测试,而且 Selenium 可以在一个或多个浏览器中执行这些测试。
Selenium 经历了三个版本:Selenium 1,Selenium 2 和 Selenium 3。Selenium 也不是简单一个工具,而是由几个工具组成,每一个工具都有其特色和应用场景。
Selenium 诞生于 2004 年,当在 ThoughtWorks 工做的 Jason Huggins 在测试一个内部应用时。做为一个聪明的家伙,他意识到相对于每次改动都须要手工进行测试,他的时间应该用得更有价值。他开发了一个能够驱动页面进行交互的 Javascript 库,能让多浏览器自动返回测试结果。那个库最终变成了 Selenium 的核心,它是 Selenium RC(远程控制)和 Selenium IDE 全部功能的基础。Selenium RC 是开拓性的,由于没有其余产品能让你使用本身喜欢的语言来控制浏览器。这就是 Selenium 1。
然而,因为它使用了基于 Javascript 的自动化引擎,而浏览器对 Javascript 又有不少安全限制,有些事情就难以实现。更糟糕的是,网站应用正变得愈来愈强大,它们使用了新浏览器提供的各类特性,都使得这些限制让人痛苦不堪。
在 2006 年,一名 Google 的工程师, Simon Stewart 开始基于这个项目进行开发,这个项目被命名为 WebDriver。此时,Google 早已经是 Selenium 的重度用户,可是测试工程师们不得不绕过它的限制进行工具。Simon 须要一款能经过浏览器和操做系统的本地方法直接和浏览器进行通话的测试工具,来解决Javascript 环境沙箱的问题。WebDriver 项目的目标就是要解决 Selenium 的痛点。
到了 2008 年,Selenium 和 WebDriver 两个项目合并。Selenium 有着丰富的社区和商业支持,但 WebDriver 显然表明着将来的趋势。二者的合并为全部用户提供了一组通用功能,而且借鉴了一些测试自动化领域最闪光的思想。这就是 Selenium 2。
2016 年,Selenium 3 诞生。移除了再也不使用的 Selenium 1 中的 Selenium RC,而且官方重写了全部的浏览器驱动。
Selenium 工具集
Selenium IDE
Selenium IDE (集成开发环境) 是一个建立测试脚本的原型工具。它是一个 Firefox 插件,实现简单的浏览器操做的录制与回放功能,提供建立自动化测试的建议接口。Selenium IDE 有一个记录功能,能记录用户的操做,而且能选择多种语言把它们导出到一个可重用的脚本中用于后续执行。
Selenium RC
Selenium RC 是selenium 家族的核心工具,Selenium RC 支持多种不一样的语言编写自动化测试脚本,经过selenium RC 的服务器做为代理服务器去访问应用从而达到测试的目的。
selenium RC 使用分Client Libraries 和Selenium Server。
Client Libraries 库主要主要用于编写测试脚本,用来控制selenium Server 的库。
Selenium Server 负责控制浏览器行为,总的来讲,Selenium Server 主要包括3 个部分:Launcher、Http Proxy、Core。
Selenium Grid
Selenium Grid 使得 Selenium RC 解决方案能提高针对大型的测试套件或者哪些须要运行在多环境的测试套件的处理能力。Selenium Grid 能让你并行的运行你的测试,也就是说,不一样的测试能够同时跑在不一样的远程机器上。这样作有两个有事,首先,若是你有一个大型的测试套件,或者一个跑的很慢的测试套件,你可使用 Selenium Grid 将你的测试套件划分红几份同时在几个不一样的机器上运行,这样能显著的提高它的性能。同时,若是你必须在多环境中运行你的测试套件,你能够得到多个远程机器的支持,它们将同时运行你的测试套件。在每种状况下,Selenium Grid 都能经过并行处理显著地缩短你的测试套件的处理时间。
Selenium WebDriver
WebDriver 是 Selenium 2 主推的工具,事实上WebDriver是Selenium RC的替代品,由于Selenium须要保留向下兼容性的缘由,在 Selenium 2 中, Selenium RC才没有被完全的抛弃,若是使用Selenium开发一个新的自动化测试项目,那么咱们强烈推荐使用Selenium2 的 WebDriver进行编码。另外, 在Selenium 3 中,Selenium RC 被移除了。
Python 语言的选择,便捷
测试人员的编程能力广泛不是很强,而Python做为一种脚本语言,不只功能强大,并且语法优美,支持多种自动化测试工具,并且学习上手比较容易。
Python的社区发展比较好,有着很是多的文档和支持库,另外Python也能够在Web开发、数据处理、科学计算等纵多领域有着很是好的应用前景。
对于有必定编程基础的人员,使用Python做为自动化测试的语言能够很是顺畅的转换,几乎没有学习成本。同时Python是标准的面向对象的编程语言,对于C#、Java等面向对象的语言有着很是好的示例做用,经过Python的示例能够很是轻松的举一反三,使用其余语言进行Selenium2.0的WebDriver的使用。
读音:/'paɪθən/
Python的创始人为Guido Van Rossum。1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,作为ABC 语言的一种继承。之因此选中Python(大蟒蛇的意思)做为程序的名字,是由于他是一个叫Monty Python的喜剧团体的爱好者。
Python 语言除了在自动化测试领域有出色的表现外,在系统编程,网络编程,web 开发,GUI开发,科学计算,游戏开发等多个领域应用很是普遍,并且具备很是良好的社区支持。也就是说学习和掌握python 编程,实际上是为你打开了一道更广阔的大门。
使用的工具集
IDE: Jetbrains PyCharm
语言: Python
工具: Selenium WebDriver
源代码管理: SVN/Git
1.2.2 JetBrains PyCharm 使用
JetBrains PyCharm 的介绍
PyCharm 是 JetBrains 公司针对Python推出的IDE(Integrated Development Environment,集成开发环境)。是目前最好的Python IDE之一。目前包含了两个版本:
社区版,Community Edition
专业版,Professional Edition
付费
比社区版主要多了Web开发框架
咱们推荐使用免费的社区版本,进行Python脚本的编写和自动化测试执行。
PyCharm能够在官网下载,http://www.jetbrains.com
PyCharm 安装后,若是也安装过 Python 环境,能够直接进行操做。不然请在 1.2.3 中安装好 Python,再使用 PyCharm。
安装按照默认的步骤安装
使用方式
Create New Project:
建立新的项目,选择项目建立的位置,选择Python的解释器
设置location,项目的路径和名称
名称必须以英文字母开头
名称不能够有空格
位置不能够在 C:\Pytho34中,应该放到普通的目录中
设置interpreter
一个电脑能够装多个 Python
这里选择一个你须要的 Pythpn
新建Python文件
在建立的文件中编写第一个Python语句
print("hello Python!")
右键该文件,选择Run hello,运行该语句,在下面的运行框中会显示运行结果
C:\Python35\python.exe D:/Git/WeekendSelenium/untitled/hello.py
hello python!
Process finished with exit code 0
如图
Open
打开已经存在的项目,好比别人发给你的项目,或者已经建立过的项目
安装后进行设置以下:
设置行号的显示
在PyCharm 里,显示行号有两种办法:
临时设置(不推荐)。右键单击行号处,选择 Show Line Numbers。
可是这种方法,只对一个文件有效,而且,重启PyCharm 后消失。
永久设置。File --> Settings -->Editor -->Appearance , 以后勾选Show Line Numbers。
设置字体
选择 Settings | Editor | Colors & Fonts | Fonts
Save AS 主题
选择 Source Code Pro(建议选择,等宽字体)
SVN / Git 在工具中的集成
源代码管理工具(VCS, version control system)
若是TortoiseSVN版本低于 1.8,须要先升级安装1.8以上的版本
选择SVN(git)做为代码的源代码管理工具。集成在PyCharm中的步骤以下
代码已经存在在SVN repo中:把代码放到SVN在本地签出(check out)的文件夹目录中,例如 D:\SVN\XXProject\Trunck
代码没有建立:在本地的SVN项目文件夹中新建项目,用PyCharm打开,提交。
用PyCharm打开 刚刚部署的代码
选择PyCharm的 VCS|Enable VCS integration,选择 Subversion(svn) 或者 Git
右键项目文件的根目录,选择 Subversion | add to VCS
右键项目文件的根目录,或者选 VCS | Commit Directory...
天天打开代码后,右键项目文件的根目录,首先 Subversion | update project
若是有冲突,先本地手工保存你作的修改(备份你的文件到其余地方,SVN目录以外的地方,而后Revert)
1.2.3 Selenium 的环境搭建
在 Windows 搭建和部署 Selenium 工具
主要包括两个步骤:
安装 Python 语言
Python的官方网站:http://www.python.org
Python 目前并行了两套版本,2.x 和 3.x。若是你以前没有 Python 的使用经验,建议使用 Python 3.x 版本。两套版本互相不兼容,而且 Python 从 3.5(含)开始,再也不支持 Windows XP 系统,请注意。
选择安装目录
3.4或者3.4如下的版本,都是 C:\python34
3.5以上的目录,默认装我的文件夹,建议用相似上面的目录,好比C:\python35
勾选添加环境变量
勾选Add Python.exe to PATH
安装过程当中不要关闭弹出来的命令行窗口
关于 Python 的安装,也能够选择一些第三方的Python 安装包,典型的有 Anaconda3,这样的包有丰富的第三方库,在使用 Python 的过程当中会更加方便。
Anaconda 的官网:https://www.continuum.io/anaconda-overview
安装 Selenium 工具包
因为 安装好的 Python 默认有 pip Python 包管理工具,能够经过 pip 很是方便的安装 Selenium。
启动命令行工具:Win+R | 输入 cmd | 回车
输入命令:
pip install selenium
该命令的执行须要有互联网联网环境。此外该命令有如下几种选项可使用
安装指定的版本,例如安装指定的 Selenium 3.4.3
pip install selenium==3.4.3
安装最新版的 Selenium
pip install -U selenium
# -U 也能够用 --upgrade
pip install --upgrade selenium
卸载安装当前的 Selenium
pip uninstall selenium
固然,若是您的机器处于非接入互联网的环境,您能够事先下载 Selenium 的 Python 安装包,再进行手动安装。
官方下载地址:https://pypi.python.org/pypi/selenium
上述地址会下载最新版的 Selenium,目前最早版的是 3.4.3,您也能够根据如下路径下载指定的 3.4.3
Selenium 3.4.3 下载地址:https://pypi.python.org/pypi/selenium/3.4.3#downloads
下载后,解压该压缩包
而后用命令行进入该压缩包的根目录,输入命令进行安装
python setup.py install
配置 浏览器 和 驱动
Selenium 2 能够默认支持Firefox 46.0或者更低版本,对于其余浏览器须要额外安装驱动。
Selenium 3 对于全部的浏览器都须要安装驱动,本文以 Chrome 和 Firefox、IE为例设置浏览器和驱动。
ChromeDriver下载地址:http://chromedriver.storage.googleapis.com/index.html
ChromeDriver 与 Chrome 对应关系表:
ChromeDriver版本 支持的Chrome版本
v2.31 v58-60
v2.30 v58-60
v2.29 v56-58
v2.28 v55-57
v2.27 v54-56
v2.26 v53-55
v2.25 v53-55
v2.24 v52-54
v2.23 v51-53
v2.22 v49-52
v2.21 v46-50
v2.20 v43-48
GeckoDriver下载地址:https://github.com/mozilla/geckodriver/releases
GeckoDriver 与 Firefox 的对应关系表:
GeckoDriver版本 支持的Firefox版本
v0.18.0 v56
v0.17.0 v55
v0.16.0 v54,须要Selenium 3.4或者以上
v0.15.0 v53,须要Selenium 3.3或者以上
IEDriverServer下载地址:http://selenium-release.storage.googleapis.com/index.html
IEDriverServer 的版本须要与 Selenium 保持严格一致。
浏览器驱动的配置
首先,将下载好的对应版本的浏览器安装。
其次,在 Python 的根目录中,放入浏览器驱动。
最好再重启电脑,通常状况下不重启也能够的。
1.3 Selenium 的最简脚本
经过上一节的环境安装成功之后,咱们能够进行第一个对Selenium 的使用,就是最简脚本编写。脚本以下:
# 声明一个司机,司机是个Chrome类的对象
driver = webdriver.Chrome()
# 让司机加载一个网页
driver.get("http://demo.ranzhi.org")
# 给司机3秒钟去打开
sleep(3)
# 开始登陆
# 1. 让司机找用户名的输入框
we_account = driver.find_element_by_css_selector('#account')
we_account.clear()
we_account.send_keys("demo")
# 2. 让司机找密码的输入框
we_password = driver.find_element_by_css_selector('#password')
we_password.clear()
we_password.send_keys("demo")
# 3. 让司机找 登陆按钮 并 单击
driver.find_element_by_css_selector('#submit').click()
sleep(3)
实际上一段20行的代码,也不能算太少了。可是这段代码的使用,确实体现了 Selenium 的最简单的使用。咱们在下面内容进行阐述。
关于面向对象编程
经过前面的介绍,咱们知道 Selenium 支持多种语言,而且推荐使用面向对象的方式进行编程。接下来咱们将着重介绍如何使用面向对象的方式进行编程。
咱们利用 Python 进行面向对象编程,须要首先了解一个概念:类
类
类是任何面向对象编程的语言的基本组成,描述了使用的基本方法。咱们可能在目前,还不是特别明白类的含义,可是咱们能够经过类的使用,来进一步了解。
类的使用
类,经过实例化进行使用。好比有一个类: Driver,该类有一个方法: head(road)
那么关于这个类的使用,只须要两个步骤:
实例化该类:d = Driver()
调用类的方法:d.head("中山路")
了解上述例子和使用之后,咱们来看具体的 Selenium 的使用。
具体的对象的使用
在面向对象的理念看来,任何的编码,都是由对象而来的,这里也不例外。和以前介绍 WebDriver 时候的描述对应,咱们须要用到两种主要的类,并将其实例化。
WebDriver 类:主要靠直接实例化该类为对象,而后用其对象直接调用该类的方法和属性
WebElement 类:主要经过 WebDriver 类实例化的对象,经过对页面元素的查找,获得 WebElement 类的对象,而后调用该类的方法和属性。
上述代码中,使用了一个 WebDriver 类 的对象,即第2行,声明了该类的对象,并赋值给变量 driver,接着变量 driver 做为 WebDriver 类的对象,使用了多个 WebDriver 类的方法。
注意:Chrome 是 WebDriver 的子类,是 WebDriver 类的一种
get(url): 第5行,打开网址
find_element_by_css_selector(selector): 第十二、1七、22行都使用了该方法,同时经过对该方法的调用,分别各产生了一个 WebElement类的对象,we_account,we_password和最后一个匿名的对象,并经过产生的三个对象,调用 WebElement 类的方法
clear():清理页面元素中的文字
send_keys(text):给页面元素中,输入新的文字
click():鼠标左键点击页面元素
正是经过这样的面向对象的方式,产生 Web司机(WebDriver类的对象),而且经过 Web司机不懈的努力,寻找到各类 Web元素(WebElement类的对象)进行操做,这样便实现了 Selenium WebDriver 做为一款出色的浏览器测试工具,进行浏览器UI界面的自动化测试的代码编写和用例执行。
1.4 Selenium WebDriver API 的使用
经过上述最简脚本的使用,咱们能够来进一步了解 Selenium 的使用。事实上,上一节用的,即是 Selenium 的 WebDriver API。API(Application Programming Interface,应用程序编程接口,即经过编程语言,操做 WebDriver 的方法集合)
Selenium WebDriver API 官方参考:http://seleniumhq.github.io/selenium/docs/api/py/
具体API文档地址:https://seleniumhq.github.io/selenium/docs/api/py/api.html
API 使用: 用现成的类(大部分状况)的方法进行编程
WebDriver
WebElement
API 文档
编程使用说明
介绍了每一个方法的使用
方法的做用
方法的参数
方法的返回值
1.4.1 控制浏览器
浏览器的控制也是自动化测试的一个基本组成部分,咱们能够将浏览器最大化,设置浏览器的高度和宽度以及对浏览器进行导航操做等。
# 浏览器打开网址
driver.get("https://www.baidu.com")
# 浏览器最大化
driver.maximize_window()
# 设置浏览器的高度为800像素,宽度为480像素
driver.set_window_size(480, 800)
# 浏览器后退
driver.back()
# 浏览器前进
driver.forward()
# 浏览器关闭
driver.close()
# 浏览器退出
driver.quit()
1.4.2 元素定位操做
WebDriver提供了一系列的定位符以便使用元素定位方法。常见的定位符有如下几种:
id
name
class name
tag
link text
partial link text
xpath
css selector
那么咱们如下的操做将会基于上述的定位符进行定位操做。
对于元素的定位,WebDriver API能够经过定位简单的元素和一组元素来操做。在这里,咱们须要告诉Selenium如何去找元素,以致于他能够充分的模拟用户行为,或者经过查看元素的属性和状态,以便咱们执行一系列的检查。
在Selenium2中,WebDriver提供了多种多样的find_element_by方法在一个网页里面查找元素。这些方法经过提供过滤标准来定位元素。固然WebDriver也提供了一样多种多样的find_elements_by的方式去定位多个元素。
尽管上述的方式,能够进行元素定位,实际上咱们也是更多的用组合的方式进行元素定位。
方法Method 描述Description 参数Argument 示例Example
id 该方法经过ID的属性值去定位查找单个元素 id: 须要被查找的元素的ID find_element_by_id('search')
name 该方法经过name的属性值去定位查找单个元素 name: 须要被查找的元素的名称 find_element_by_name('q')
class name 该方法经过class的名称值去定位查找单个元素 class_name: 须要被查找的元素的类名 find_element_by_class_name('input-text')
tag_name 该方法经过tag的名称值去定位查找单个元素 tag: 须要被查找的元素的标签名称 find_element_by_tag_name('input')
link_text 该方法经过连接文字去定位查找单个元素 link_text: 须要被查找的元素的连接文字 find_element_by_link_text('Log In')
partial_link_text 该方法经过部分连接文字去定位查找单个元素 link_text: 须要被查找的元素的部分连接文字 find_element_by_partial_link_text('Long')
xpath 该方法经过XPath的值去定位查找单个元素 xpath: 须要被查找的元素的xpath find_element_by_xpath('//*[@id="xx"]/a')
css_selector 该方法经过CSS选择器去定位查找单个元素 css_selector: 须要被查找的元素的ID find_element_by_css_selector('#search')
接下来的列表将会详细展现find_elements_by的方法集合。这些方法依据匹配的具体标准返回一系列的元素。
方法Method 描述Description 参数Argument 示例Example
id 该方法经过ID的属性值去定位查找多个元素 id: 须要被查找的元素的ID find_elements_by_id('search')
name 该方法经过name的属性值去定位查找多个元素 name: 须要被查找的元素的名称 find_elements_by_name('q')
class_name 该方法经过class的名称值去定位查找多个元素 class_name: 须要被查找的元素的类名 find_elements_by_class_name('input-text')
tag_name 该方法经过tag的名称值去定位查找多个元素 tag: 须要被查找的元素的标签名称 find_elements_by_tag_name('input')
link_text 该方法经过连接文字去定位查找多个元素 link_text: 须要被查找的元素的连接文字 find_elements_by_link_text('Log In')
partial_link_text 该方法经过部分连接文字去定位查找多个元素 link_text: 须要被查找的元素的部分连接文字 find_elements_by_partial_link_text('Long')
xpath 该方法经过XPath的值去定位查找多个元素 xpath: 须要被查找的元素的xpath find_elements_by_xpath("//div[contains(@class,'list')]")
css_selector 该方法经过CSS选择器去定位查找多个元素 css_selector: 须要被查找的元素的ID find_element_by_css_selector('.input_class')
依据ID查找
请查看以下HTML的代码,以便实现经过ID的属性值去定义一个查找文本框的查找:
<input id="search" type="text" name="q" value=""
class="input-text" maxlength="128" autocomplete="off"/>
根据上述代码,这里咱们使用find_element_by_id()的方法去查找搜索框而且检查它的最大长度maxlength属性。咱们经过传递ID的属性值做为参数去查找,参考以下的代码示例:
def test_search_text_field_max_length(self):
# get the search textbox
search_field = self.driver.find_element_by_id("search")
# check maxlength attribute is set to 128
self.assertEqual("128", search_field.get_attribute("maxlength"))
若是使用find_elements_by_id()方法,将会返回全部的具备相同ID属性值的一系列元素。
依据名称name查找
这里仍是根据上述ID查找的HTML代码,使用find_element_by_name的方法进行查找。参考以下的代码示例:
# get the search textbox
self.search_field = self.driver.find_element_by_name("q")
一样,若是使用find_elements_by_name()方法,将会返回全部的具备相同name属性值的一系列元素。
依据class name查找
除了上述的ID和name的方式查找,咱们还可使用class name的方式进行查找和定位。
事实上,经过ID,name或者类名class name查找元素是最提倡推荐的和最快的方式。固然Selenium2 WebDriver也提供了一些其余的方式,在上述三类方式条件不足,查找无效的时候,能够经过这些其余方式来查找。这些方式将会在后续的内容中讲述。
请查看以下的HTML代码,经过改代码进行练习和理解.
<button type="submit" title="Search" class="button">
<span><span>Search</span></span>
</button>
根据上述代码,使用find_element_by_class_name()方法去定位元素。
def test_search_button_enabled(self):
# get Search button
search_button = self.driver.find_element_by_class_name("button")
# check Search button is enabled
self.assertTrue(search_button.is_enabled())
一样的若是使用find_elements_by_class_name()方法去定位元素,将会返回全部的具备相同name属性值的一系列元素。
依据标签名tag name查找
利用标签的方法相似于利用类名等方法进行查找。咱们能够轻松的查找出一系列的具备相同标签名的元素。例如咱们能够经过查找表中的<tr>来获取行数。
下面有一个HTML的示例,这里在无序列表中使用了<img>标签。
<ul class="promos">
<li>
<a href="http://demo.magentocommerce.com/home-decor.html">
<img src="/media/wysiwyg/homepage-three-column-promo-
01B.png" alt="Physical & Virtual Gift Cards">
</a>
</li>
<li>
<a href="http://demo.magentocommerce.com/vip.html">
<img src="/media/wysiwyg/homepage-three-column-promo-
02.png" alt="Shop Private Sales - Members Only">
</a>
</li>
<li>
<a href="http://demo.magentocommerce.com/accessories/
bags-luggage.html">
<img src="/media/wysiwyg/homepage-three-columnpromo-
03.png" alt="Travel Gear for Every Occasion">
</a>
</li>
</ul>
这里面咱们使用find_elements_by_tag_name()的方式去获取所有的图片,在此以前,咱们将会使用find_element_by_class_name()去获取到指定的<ul>。
具体代码以下:
def test_count_of_promo_banners_images(self):
# get promo banner list
banner_list = self.driver.find_element_by_class_name("promos")
# get images from the banner_list
banners = banner_list.find_elements_by_tag_name("img")
# check there are 20 tags displayed on the page
self.assertEqual(20, len(banners))
依据连接文字link查找
连接文字查找一般比较简单。使用find_element_by_link_text请查看如下示例
<a href="#header-account" class="skip-link skip-account">
<span class="icon"></span>
<span class="label">ACCOUNT Description</span>
</a>
测试代码以下:
def test_my_account_link_is_displayed(self):
# get the Account link
account_link =
self.driver.find_element_by_link_text("ACCOUNT Description")
# check My Account link is displayed/visible in
# the Home page footer
self.assertTrue(account_link.is_displayed())
依据部分连接文字partial text查找
这里依旧使用上述的列子进行代码编写:
def test_account_links(self):
# get the all the links with Account text in it
account_links = self.driver.\
find_elements_by_partial_link_text("ACCOUNT")
# check Account and My Account link is
# displayed/visible in the Home page footer
self.assertTrue(2, len(account_links))
依据XPath进行查找
XPath是一种在XML文档中搜索和定位节点node的一种查询语言。全部的主流Web浏览器都支持XPath。Selenium2能够用强大的XPath在页面中查找元素。
经常使用的XPath的方法有starts-with(),contains()和ends-with()等
若想要了解更多关于XPath的内容,请查看http://www.w3schools.com/XPath/
以下有一段HTML代码,其中里面的<img>没有使用ID,name或者类属性,因此咱们没法使用以前的方法。亚这里咱们能够经过<img>的alt属性,定位到指定的tag。
<ul class="promos">
<li>
<a href="http://demo.magentocommerce.com/home-decor.html">
<img src="/media/wysiwyg/homepage-three-column-promo-
01B.png" alt="Physical & Virtual Gift Cards">
</a>
</li>
<li>
<a href="http://demo.magentocommerce.com/vip.html">
<img src="/media/wysiwyg/homepage-three-column-promo-
02.png" alt="Shop Private Sales - Members Only">
</a>
</li>
<li>
<a href="http://demo.magentocommerce.com/accessories/
bags-luggage.html">
<img src="/media/wysiwyg/homepage-three-columnpromo-
03.png" alt="Travel Gear for Every Occasion">
</a>
</li>
</ul>
具体代码以下:
def test_vip_promo(self):
# get vip promo image
vip_promo = self.driver.\
find_element_by_xpath("//img[@alt='Shop Private Sales - Members Only']")
# check vip promo logo is displayed on home page
self.assertTrue(vip_promo.is_displayed())
# click on vip promo images to open the page
vip_promo.click()
# check page title
self.assertEqual("VIP", self.driver.title)
固然,若是使用find_elements_by_xpath()的方法,将会返回全部匹配了XPath查询的元素。
依据CSS选择器进行查找
CSS是一种设计师用来描绘HTML文档的视觉的层叠样式表。通常来讲CSS用来定位多种多样的风格,同时能够用来是一样的标签使用一样的风格等。相似于XPath,Selenium2也可使用CSS选择器来定位元素。
请查看以下的HTML文档。
<div class="minicart-wrapper">
<p class="block-subtitle">Recently added item(s)
<a class="close skip-link-close" href="#" title="Close">×</a>
</p>
<p class="empty">You have no items in your shopping cart.
</p>
</div>
咱们来建立一个测试,验证这些消息是否正确。
def test_shopping_cart_status(self):
# check content of My Shopping Cart block on Home page
# get the Shopping cart icon and click to open the
# Shopping Cart section
shopping_cart_icon = self.driver.\
find_element_by_css_selector("div.header-minicart
span.icon")
shopping_cart_icon.click()
# get the shopping cart status
shopping_cart_status = self.driver.\
find_element_by_css_selector("p.empty").text
self.assertEqual("You have no items in your shopping cart.",
shopping_cart_status)
# close the shopping cart section
close_button = self.driver.\
find_element_by_css_selector("div.minicart-wrapper
a.close")
close_button.click()
特殊 iframe 操做
iframe 元素会建立包含另一个文档的内联框架(即行内框架)。
iframe: 紫禁城
在一个<html>中,包含了另外一个<html>
示例
<html>
<head>
<title>iframe示例</title>
</head>
<body>
<h1>
这里是H1,标记了标题
</h1>
<p>
这里是段落,标记一个段落,属于外层
</p>
<div>
<iframe id="iframe-1">
<html>
<body>
<p>
这里是个段落,属于内层,内联框架中的
</p>
<div id="div-1">
<p class="hahahp">
这里是div中的段落,须要被定位
</p>
</div>
</body>
</html>
</iframe>
</div>
</body>
</html>
须要定位上面示例中的<p>:这里是div中的段落,须要被定位
以下是selenium WebDiriver的代码
## 查找并定位 iframe
element_frame = driver.find_element_by_css_selector('#iframe-1')
## 切换到刚刚查找到的 iframe
driver.switch_to.frame(element_frame)
## 定位 <p>
driver.find_element_by_css_selector('#div-1 > p')
## TODO....
## 退出刚刚切换进去的 iframe
driver.switch_to.default_content()
特殊 Select 操做
<select> 是选择列表
Select 是个selenium的类selenium.webdriver.support.select.Select
Select 类的路径:
C:\Python35\Lib\site-packages\selenium\webdriver\support\select.py
<select id="brand">
<option value ="volvo">Volvo</option>
<option value ="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
示例,选择 Audi
## 查找并定位到 select
element_select = driver.find_element_by_css_selector('#brand')
## 用Select类的构造方法,实例化一个对象 object_select
object_select = Select(element_select)
## 操做 object_select
object_select.select_by_index(3)
## 也能够这样
object_select.select_by_value('audi')
## 还能够这样
object_select.select_by_visible_text('Audi')
组合操做
自动化经验的积累,须要100%按照手工的步骤进行操做。
好比步骤以下:
点击一个 <a id="customer_chosen">
自动产生了一个 <ul id="customer_list">
点击<ul>的第五个<li>
代码示例
driver.find_element_by_css_selector('#customer_chosen').click()
sleep(1)
driver.find_element_by_css_selector('#customer_list > li:nth-child(5)')
1.4.3 鼠标事件操做
Web测试中,有关鼠标的操做,不仅是单击,有时候还要作右击、双击、拖动等操做。这些操做包含在ActionChains类中。
经常使用的鼠标方法:
context_click() # 右击
double_click() # 双击
drag_and_drop() # 拖拽
move_to_element() # 鼠标停在一个元素上
click_and_hold() # 按下鼠标左键在一个元素上
例子:
# 方法模拟鼠标右键,参考代码以下:
# 引入ActionChains 类
from selenium.webdriver.common.action_chains import ActionChains
...
# 定位到要右击的元素
right =driver.find_element_by_xpath("xx")
# 对定位到的元素执行鼠标右键操做
ActionChains(driver).context_click(right).perform()
...
# 定位到要双击的元素
double = driver.find_element_by_xpath("xxx")
# 对定位到的元素执行鼠标双击操做
ActionChains(driver).double_click(double).perform()
1.4.4 键盘事件操做
键盘操做常常处理的以下:
代码 描述
send_keys(Keys.BACKSPACE) 删除键(BackSpace)
send_keys(Keys.SPACE) 空格键(Space)
send_keys(Keys.TAB) 制表键(Tab)
send_keys(Keys.ESCAPE) 回退键(Esc)
send_keys(Keys.ENTER) 回车键(Enter)
send_keys(Keys.CONTROL,'a') 全选(Ctrl+A)
send_keys(Keys.CONTROL,'c') 复制(Ctrl+C)
代码以下
from selenium import webdriver
# 引入Keys 类包
from selenium.webdriver.common.keys import Keys
import time
driver = webdriver.Chrome()
driver.get("http://www.baidu.com")
# 输入框输入内容
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(3)
# 删除多输入的一个m
driver.find_element_by_id("kw").send_keys(Keys.BACK_SPACE)
time.sleep(3)
# 输入空格键+“教程”
driver.find_element_by_id("kw").send_keys(Keys.SPACE)
driver.find_element_by_id("kw").send_keys("教程")
time.sleep(3)
# ctrl+a 全选输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')
1.4.5 截图操做
截图的方法:save_screenshot(file)
1.5 unittest 单元测试框
在上一节,咱们对 Selenium WebDriver 的使用,仅仅停留在让网页自动的进行操做的阶段,并无对任何一个步骤进行“检查”。固然,这样没有“检查”的操做,其实是没有测试意义的。那么第一项,咱们须要解决的即是“检查”的问题。
所谓“检查”,实际上就是断言。对须要检查的步骤操做,经过对预先设置的指望值,和执行结果的实际值之间的对比,获得测试的结果。在这里,咱们并不须要单独的写 if 语句进行各类断定,而是可使用编程语言中对应的单元测试框架,便可解决好此类问题。
目前 Java 语言主流的单元测试框架有 JUnit 和 TestNG。Python 语言主流的单元测试框架有 unittest 。本小节的内容,主要介绍 unittest 的使用,探讨单元测试框架如何帮助自动化测试。
接下来咱们将会使用 Python 语言的unittest框架展开“检查”。unittest框架的本来的名字是PyUnit。是从JUnit 这样一个被普遍使用的 经典的Java应用开发的单元测试框架创造而来。相似的框架还有NUnit(.Net开发的单元测试框架)等。咱们可使用unittest框架为任意Python项目编写可理解的单元测试集合。如今这个unittest已经做为Python的标准库模块发布。咱们安装完Python之后,即可以直接使用unittest。
使用unittest须要如下简单的三步:
引入unittest模组
继承unittest.TestCase基类
测试方法以test开头
unittest 并未使用 Java 语言常见的注解方式,依旧停留在 比较早期的 Java 版本中依靠方法名称进行识别的方式。主要有如下两个固定名字的方法:
setUp():在每一个测试方法运行前,执行。是测试前置条件。
tearDown():在每一个测试方法运行后执行,是测试清理操做。
具体的代码以下:
## 引入unittest模组
import unittest
## 定义测试类,名字为DemoTests
## 该类必须继承unittest.TestCase基类
class DemoTests(unittest.TestCase):
## 使用'@'修饰符,注明该方法是类的方法
## setUpClass方法是在执行测试以前须要先调用的方法
## 是开始测试前的初始化工做
@classmethod
def setUpClass(cls):
print("call setUpClass()")
## 每个测试开始前的预置条件
def setUp(self):
print("call setUp()")
## 每个测试结束之后的清理工做
def tearDown(self):
print("call tearDown()")
## 测试一(务必以test开头)
def test_01(self):
print("call test_01()")
pass
## 测试三(务必以test开头)
def test_02(self):
print("call test_02()")
pass
## 测试三(务必以test开头)
def test_03(self):
print("call test_03()")
pass
## tearDownClass方法是执行完全部测试后调用的方法
## 是测试结束后的清除工做
@classmethod
def tearDownClass(cls):
print("call tearDownClass()")
# 执行测试主函数
if __name__ == '__main__':
## 执行main全局方法,将会执行上述全部以test开头的测试方法
unittest.main(verbosity=2)
须要注意步骤:
引入 unittest 模组
继承 unittest.TestCase 类
作测试用例的方法,方法以 test_ 开头
附加 setUp(), tearDown(), 在每一个 test_ 方法执行先后 进行执行
附加 setUpClass(), tearDownClass()
须要在 类实例化的对象,运行的开头和结尾进行执行。
加了星号(*)的步骤,能够不用。
上述代码运行结果以下:
call setUpClass()
call setUp()
call test_01()
call tearDown()
call setUp()
call test_02()
call tearDown()
call setUp()
call test_06()
call tearDown()
call tearDownClass()
为何选择 unittest
清晰的单元测试框架,提供 TestCase, TestSuite, TextTestRunner 等基本类
unittest 是 原生 Python 的一部分
unittest 有第三方可用的 HTML 库,能够轻松的生成 测试报告
unittest 的断言配置使用
unittest 的断言,属于 TestCase类,只要继承了该类,都可以经过 self调用断言
方法 Method 检查条件
assertEqual(a, b [, msg]) a == b,msg可选,用来解释失败的缘由
assertNotEqual(a, b [, msg] a != b,msg可选,用来解释失败的缘由
assertTrue(x [, msg]) x 是真,msg可选,用来解释失败的缘由
assertFalse(x [, msg]) x 是假,msg可选,用来解释失败的缘由
assertIsNot(a, b [, msg]) a 不是 b,msg可选,用来解释失败的缘由
1.6 为何须要封装 Selenium
什么是封装
封装是一个面向对象编程的概念,是面向对象编程的核心属性,经过将代码内部实现进行密封和包装,从而简化编程。对Selenium进行封装的好处主要有以下三个方面:
使用成本低
不须要要求全部的测试工程师会熟练使用Selenium,而只须要会使用封装之后的代码
不须要对全部的测试工程师进行完整培训。也避免工做交接的成本。
测试人员使用统一的代码库
维护成本低
经过封装,在代码发生大范围变化和迁移的时候,不须要维护全部代码,只须要变动封装的部分便可
维护代码不须要有大量的工程师,只须要有核心的工程师进行封装的维护便可
代码安全性
对做为第三方的Selenium进行封装,是代码安全的基础。
对于任何的代码的安全隐患,必须由封装来解决,使得风险可控。
使用者并不知道封装内部的代码结构。
1.7 封装的概念与基本操做
关键方法的封装思路
封装的具体示例:
找到一个指定输入框(selector),而且输入指定的字符(text)
type(selector, text)
不用在业务逻辑中,使用屡次的 find_element_by_id(...))
def type(self, selector, text):
"""
Operation input box.
Usage:
driver.type("i,el","selenium")
"""
el = self._locate_element(selector)
el.clear()
el.send_keys(text)
找到一个能够点击的元素(selector),而且点击(click)
click(selector)
def click(self, selector):
"""
It can click any text / image can be clicked
Connection, check box, radio buttons, and even drop-down box etc..
Usage:
driver.click("i,el")
"""
el = self._locate_element(selector)
el.click()
找到一个指定的frame,而且切换进去
switch_to_frame(selector)
def switch_to_frame(self, selector):
"""
Switch to the specified frame.
Usage:
driver.switch_to_frame("i,el")
"""
el = self._locate_element(selector)
self.base_driver.switch_to.frame(el)
找到一个指定的select,而且经过index进行选择
select_by_index(selector, index)
def select_by_index(self, selector, index):
"""
It can click any text / image can be clicked
Connection, check box, radio buttons, and even drop-down box etc..
Usage:
driver.select_by_index("i,el")
"""
el = self._locate_element(selector)
Select(el).select_by_index(index)
以上的代码是封装了_locate_element()的几种方法,在具体使用封装过的代码的时候,只须要简单的调用便可。接下来的重点,是介绍 _locate_element(selector)的封装方式。
查找元素:find_element_by_...)
支持各类的查找:8种方式都须要支持,必须经过 selector 显示出分类
selector中须要包含一个特殊符号
实例化 封装好的类的时候,须要约定好是什么特殊符号
强制性用硬编码 hard code来实例化,例如 , 或者 ? 或者 其余很是用字符 =>
或者,构造方法中,传递 this.byChar
要把查找到元素的返回给调用的地方:必需要有返回值,类型是 WebElement
def _locate_element(self, selector):
"""
to locate element by selector
:arg
selector should be passed by an example with "i,xxx"
"x,//*[@id='langs']/button"
:returns
DOM element
"""
if self.by_char not in selector:
return self.base_driver.find_element_by_id(selector)
selector_by = selector.split(self.by_char)[0].strip()
selector_value = selector.split(self.by_char)[1].strip()
if selector_by == "i" or selector_by == 'id':
element = self.base_driver.find_element_by_id(selector_value)
elif selector_by == "n" or selector_by == 'name':
element = self.base_driver.find_element_by_name(selector_value)
elif selector_by == "c" or selector_by == 'class_name':
element = self.base_driver.find_element_by_class_name(selector_value)
elif selector_by == "l" or selector_by == 'link_text':
element = self.base_driver.find_element_by_link_text(selector_value)
elif selector_by == "p" or selector_by == 'partial_link_text':
element = self.base_driver.find_element_by_partial_link_text(selector_value)
elif selector_by == "t" or selector_by == 'tag_name':
element = self.base_driver.find_element_by_tag_name(selector_value)
elif selector_by == "x" or selector_by == 'xpath':
element = self.base_driver.find_element_by_xpath(selector_value)
elif selector_by == "s" or selector_by == 'css_selector':
element = self.base_driver.find_element_by_css_selector(selector_value)
else:
raise NameError("Please enter a valid type of targeting elements.")
return element
面向对象编程思想的运用
构造方法
类
普通方法
封装后的方法如何被调用
使用上面的封装类,就须要指定特定的 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
具体调用示例
def login(self, account, password, keep):
"""
登陆系统
:param account:
:param password:
:param keep:
:return: 返回保持登陆复选框的 checked 值
"""
self.base_driver.type(self.LOGIN_ACCOUNT_SELECTOR, account)
self.base_driver.type(self.LOGIN_PASSWORD_SELECTOR, password)
current_checked = self.get_current_keep_value()
if keep:
if current_checked is None:
self.base_driver.click(self.LOGIN_KEEP_SELECTOR)
else:
if current_checked == "true":
self.base_driver.click(self.LOGIN_KEEP_SELECTOR)
actual_checked = self.get_current_keep_value()
self.base_driver.click(self.LOGIN_SUBMIT_SELECTOR)
sleep(2)
return actual_checked
1.8 Page-Object设计模式介绍
Page-Object设计模式的本质
Page Object设计模式是Selenium自动化测试项目的最佳设计模式之一,强调测试、逻辑、数据和驱动相互分离。
Page Object模式是Selenium中的一种测试设计模式,主要是将每个页面设计为一个Class,其中包含页面中须要测试的元素(按钮,输入框,标题等),这样在Selenium测试页面中能够经过调用页面类来获取页面元素,这样巧妙的避免了当页面元素id或者位置变化时,须要改测试页面代码的状况。当页面元素id变化时,只须要更改测试页Class中页面的属性便可。
它的好处以下:
集中管理元素对象,便于应对元素的变化
集中管理一个page内的公共方法,便于测试用例的编写
后期维护方便,不须要重复的复制和修改代码
具体的作法以下:
建立一个页面的类
在类的构造方法中,传递 WebDriver 参数。
在测试用例的类中,实例化页面的类,而且传递在测试用例中已经实例化的WebDriver对象。
在页面的类中,编写该页面的全部操做的方法
在测试用例的类中,调用这些方法
Page 如何划分
通常经过继承的方式,进行按照实际Web页面进行划分
Page-Object 类如何实现
实现的示例
Page 基类
设计了一个基本的 Page类,以便全部的页面进行继承,该类标明了一个sub page类的基本功能和公共的功能。
全局变量: self.base_driver,让全部的子类都使用的。
# 基类的变量,全部继承的类,均可以使用
base_driver = None
构造方法:
传递 driver的构造方法
# 方法
def __init__(self, driver: BoxDriver):
"""
构造方法
:param driver: ":BoxDriver" 规定了 driver 参数类型
"""
self.base_driver = driver
私有的常量:存放元素的定位符
LOGIN_ACCOUNT_SELECTOR = "s, #account"
LOGIN_PASSWORD_SELECTOR = "s, #password"
LOGIN_KEEP_SELECTOR = "s, #keepLoginon"
LOGIN_SUBMIT_SELECTOR = "s, #submit"
LOGIN_LANGUAGE_BUTTON_SELECTOR = "s, #langs > button"
LOGIN_LANGUAGE_MENU_SELECTOR = "s, #langs > ul > li:nth-child(%d) > a"
LOGIN_FAIL_MESSAGE_SELECTOR = "s, body > div.bootbox.modal.fade.bootbox-alert.in > div > div > div.modal-body"
成员方法:
每一个子类都须要的系统功能:
open
def open(self, url):
"""
打开页面
:param url:
:return:
"""
self.base_driver.navigate(url)
self.base_driver.maximize_window()
sleep(2)
全部子类(页面)都具备的业务功能
select_app
logout
Sub Pages(s)子类
具体的页面的类,定义了某个具体的页面的功能
必须继承基类
class MainPage(BasePage):
特定页面的业务
使用基类的 self.base_driver 成员变量
Tests 类
这部分描述的是具体的测试用例。
声明全局变量
base_driver = None
base_url = None
main_page = None
调用各类页面(pages)
实例化Page
self.main_page = MainPage(self.base_driver)
使用page的对象,调用成员方法
self.main_page.open(self.base_url)
self.main_page.change_language(lang)
2. 构建测试方案
2.1 数据驱动在自动化测试中的应用
什么是数据驱动
主要的数据驱动方式有两种:
经过 文本文件或者 Excel 文件存储数据,并经过程序读取数据,遍历全部的行
经过数据库存储数据,并经过程序和 SQL 脚本读取数据,遍历全部的行
经过 CSV 文件 或者 MySQL 数据库,是主流的数据驱动方式。固然数据驱动也能够结合单元测试框架的参数化测试进行编写(此部分本文不作具体描述)。
不管使用了 哪种(CSV 或者 MySQL),读取数据后都要进行遍历操做。
使用 csv
import csv
csv_file = open("xxx.csv", "r", encoding="utf8")
csv_data = csv.reader(csv_file)
for row in csv_data:
# 进行测试
# 使用字典类型
data_to_test = {
"key1": row[0],
"key2": row[1]
}
csv_file.close()
使用 MySQL
import pymysql
connect = pymysql.connect(host="xx", port=3306, user="root", passwd="xxx", db="xx")
cur = connect.cursor()
cur.execute("SELECT...")
mysql_data = cur.fetchall()
for row in mysql_data:
# 进行测试
# 使用字典类型
data_to_test = {
"key1": row[0],
"key2": row[1]
}
cur.close()
connect.close()
须要掌握的知识点:
python的字典类型 dict 类型
python的读写文件
python的读写数据库
for循环
注意资源的释放
关闭数据库游标和链接
关闭文件
2.2 测试方案的编码实现
main.py 测试入口
runner.py 测试运行器
cases 测试用例
pages 测试页面
base 底层封装与驱动
2.3 测试报告的生成
如何生成测试报告
测试报告的种类
HTML 测试报告的生成
HTML测试报告须要引入HTMLTestRunner
HTMLTestRunner是基于Python2.7的,咱们的课程讲义基于Python3.x,那么须要对这个文件作必定的修改。
测试的示例代码以下
# 声明一个测试套件suite = unittest.TestSuite()# 添加测试用例到测试套件suite.addTest(RanzhiTests("test_ranzhi_login")) # 建立一个新的测试结果文件buf = open("./result.html", "wb") # 声明测试运行的对象runner = HTMLTestRunner.HTMLTestRunner(stream=buf, title="Ranzhi Test Result", description="Test Case Run Result")# 运行测试,而且将结果生成为HTMLrunner.run(suite) # 关闭文件输出buf.close()在这里向你们推荐一个学习交流群,里面有小伙伴整理好的自动化资料上传在群文件,欢迎你们加群下载:672899761,