Selenium自动化测试——基于 Python 语言

978-7-115-46174-2
作者: 【印度】冈迪察.U(Unmesh Gundecha )
译者: 金鑫熊志男
编辑: 张涛

图书目录:

详情

本软件测试实用指南探讨了用Selenium的 WebDriver API 为在浏览器上复杂操作进行简单化实现web 应用程序测试的过程,为web 应用程序测试创建自动化测试脚本带来了便利,本书最大的特色是引入了 Python编程,使用 Python 的单元测试模块,读者可以编写测试用例中的Selenium。它会同时帮助你提高实际测试技能与 Python 和Selenium应用的技巧。

图书摘要

版权信息

书名:Selenium自动化测试——基于 Python 语言

ISBN:978-7-115-46174-2

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 著    Unmesh Gundecha

  译    熊志男

  责任编辑 张 涛

• 人民邮电出版社出版发行  北京市丰台区成寿寺路11号

  邮编 100164  电子邮件 315@ptpress.com.cn

  网址 http://www.ptpress.com.cn

• 读者服务热线:(010)81055410

  反盗版热线:(010)81055315


Copyright © Packt Publishing 2014. First published in the English language under the title“Learning Selenium Testing Tools with Python”,ISBN 978-1-78398-350-6.

All rights reserved.

本书中文简体字版由Packt Publishing公司授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式或任何手段复制和传播。

版权所有,侵权必究。


Selenium是一个主要用于Web应用程序自动化测试的工具集合,在行业内已经得到广泛的应用。本书介绍了如何用Python语言调用Selenium WebDriver接口进行自动化测试。主要内容为:基于Python 的 Selenium WebDriver 入门知识、第一个Selenium Python脚本、使用unittest 编写单元测试、生成HTML格式的测试报告、元素定位、Selenium Python API 介绍、元素等待机制、跨浏览器测试、移动端测试、编写一个iOS测试脚本、编写一个Android测试脚本、Page Object与数据驱动测试、Selenium WebDriver的高级特性、第三方工具与框架集成等核心技术。

本书适合任何软件测试人员阅读,也适合作为大专院校师生的学习用书和培训学校的教材。


认识熊志男是在中国质量大会BQConf的活动上,交谈间很快就被志男对于测试领域的见解和趋势展望所折服,而这不仅仅是因为他有丰富的测试经验,而且还因为他作为测试窝的联合创始人,对国内外测试行业有深入的了解密不可分。本书正是一个例证。

尽管国内测试行业宣扬自动化测试已经很多年了,但是我们很难在自动化测试领域招聘到经验丰富的工程师,这说明自动化测试并没有成为国内测试领域的主流。

是因为测试人员不够努力导致的吗?我并不这么认为。

很多公司对于测试的投入是希望知道产品有多少缺陷、能否按时上线,所以相应的测试人员的工作都聚焦于如何高效地编写和执行测试用例,而自动化测试并不是第一选择。因为在上线压力巨大的情况下,如果不能评估出自动化测试的投入产出比,很难让项目经理在自动化测试上进行投入。所以倘若有实践自动化测试的想法,往往需要测试人员付出自己的时间来熟悉框架、编写和维护自动化测试。而如果不是事先对测试框架有了比较深入的认识,依靠自身自发进行自动化测试,并不会带来效率的明显提升。这样不仅会让项目经理失去信心,恐怕测试人员自己也心存疑虑了。

如果单从技术上考虑,究竟是什么阻碍着测试人员广泛使用自动化测试呢?首先,如果没有一个通用的测试框架,那么每做一个项目,测试人员就得学习一套新的工具/框架,这样的学习成本太高了。在工期很紧的情况下更是如此。其次,自动化测试的编写实际上是进行编码,如果使用Java和C#这些编程语言编写自动化测试,由于测试人员很难全面掌握这些语言的开发技巧,容易导致编写出的自动化测试代码比产品代码出现更多的缺陷。

本书直击这两方面,为测试人员解除了后顾之忧。

(1)Selenium WebDriver作为业界通用的测试框架,不仅是Web测试的标准,在移动测试领域也是底层的核心驱动框架。所以掌握了Selenium WebDriver,可以让我们在为Web产品和移动产品编写自动化测试时游刃有余。

(2)Python作为动态语言,简化了严格的编程语法,使测试人员更容易掌握。同时Python也提供了丰富的API和扩展,测试人员可以很便利地调用或者集成其他语言编写的程序和类库,提高编写自动化测试的效率。

本书在讲述自动化测试编写的同时,结合业界主流的自动化测试开发模式,向读者介绍了多种测试相关知识(如BDD和持续集成)。非常推荐对测试有激情,希望快速提升自动化测试能力的朋友阅读本书。

黄 勇     

现任ThoughtWorks中国区QA Lead


起初接到本书的翻译邀约时,内心还是有一些困惑的。针对软件测试行业,特别是基于Web自动化测试领域,Selenium已经是广泛使用的工具之一了,而且已被诸多测试同行认可并使用。为此,我们查阅了国内大量相关书籍或文章,发现当前Selenium的初学门槛其实并不高,测试工程师具备有功能测试经验,加之对Web前端技术的一定程度的理解,外加较熟练地掌握一门脚本语言,经过一段时间的项目锤炼,都能基本应对日常自动化测试任务。不过与此同时,我们也发现很多初学者遇到的诸多困惑,又或者在深入学习过程中难以克服的瓶颈。

行业内,能系统性介绍WebDriver原理、多类型Server运行方式、单元测试以及如何使用Python调用Selenium WebDriver接口的具体实例的材料相对零散。直到《Learning Selenium Testing Tools with Python》中文版的出版,使得我们有机会较为全面,并且系统性地学习用单一脚本语言开发Web自动化测试的具体实践,作者独特的创作逻辑,使得本书前后实例相互对照,并且首尾呼应。既诠释原理,又能使读者进入实战,还有“干货”满满的“提醒与备注”,是一本不可多得的自动化测试指导书。这也是我们译著这本书最重要的原因了。

本书的作者Unmesh Gundecha有着极为丰富构建自动化测试解决方案的经验。主导开发过大量商业或开源的自动化测试工具。曾供职微软。在2012年编著过《Selenium Testing Tools Cookbook》一书,颇为畅销;在2015年下半年又更新发布了第二版。作者文笔犀利,逻辑之间环环相扣,语言诙谐,妙笔生花。

多年的技术文章翻译经验,使我们清晰地认识到,倘若停留在专业翻译层面,想必本书的可读性,以及作者的诸多表述,都难以顺利地传递给中文读者。所以我与熊志男(本书合译者),多次调整翻译策略。由传统的分章节翻译,到“按作者编著脉络”组织分工。由专业词汇翻译,到统一关键词口径,甚至到整句、整段打乱重组。诸如此类的一些做法,都是为了保证我们的译著质量更加符合测试同行的阅读习惯,便于学习与加深印象。

好在翻译过程中,与熊志男相互鼓励,包括审核团队不厌其烦的讨论、PK、一起揣摩作者意图。大家的专业、包容、豁达、自信,让这本书的中文译著得以完成。特别感谢参与翻译工作的张欣欣、谢满彬、谢柳娜。感谢测试窝网译文团队的多次审校。

翻译别人的图书,好似在反刍,再精彩也是在讲别人的故事。期待有一天,有机会能够讲讲我们自己的故事给广大同行。由于译者的水平有限,难免会有偏差疏漏。若有欠妥之处,欢迎指正,编辑联系邮箱zhangtao@ptpress.com.cn。

金 鑫


在互联网行业迅速发展的今天,编写自动化脚本的技能,已经逐渐成为 Web 测试人员的标配。

Python 作为备受测试人员青睐的语言之一,非常适合处理日常工作中的数据和文本问题。

Selenium 更是 UI 自动化测试的利器,但要迅速掌握并熟练运用到项目中,绝非易事。

本书围绕 Selenium 的使用展开,编排有序,通俗易懂,对于没有 UI 自动化测试经验的读者,将起到事半功倍的效果。

——Ping++ 质量负责人 吴子腾

Unmesh Gundecha编著的《Selenium Testing Tools Cookbook》,俗称“Selenium菜谱”,是我一直推荐给身边WebDriver初学者的书籍,只是很遗憾一致未被翻译成中文版本出版。

该书作为“菜谱”的Python姊妹篇,秉承了“菜谱”的内容详实,案例丰富,行文流畅等特点,是一本WebDriver入门的绝佳教材。

——陈冬严 ,浙江大学硕士,具有10年软件测试和团队管理的工作经验,先后服务于领先的ITSM、PLM软件研发企业,现于某金融行业核心机构IT规划部门担任项目管理工作。业余时间喜欢园艺。《精通自动化测试框架设计》一书的作者。


Unmesh Gundecha拥有计算机软件硕士学位,在软件开发与测试领域有着12年的工作经验。无论是在应对业界标准,还是定制需求下,他都有着丰富的构建自动化测试解决方案的经验。与此同时,他还主导开发了大量商业或开源的自动化测试工具。

他曾供职于微软公司,从事开发有关的工作。目前在印度的一家跨国企业从事测试架构师工作,在Ruby、Java、iOS、Android和PHP的项目中有着极丰富的开发与测试经验。


另外,本书能顺利编写完成,离不开很多技术同行的帮助与审阅,感谢他们花费了大量的时间为本书提供了非常有价值的反馈。

感谢各位专家、同事和朋友,特别是Yuri Weinstein给予我很多帮助与鼓励。


Adil Imroz是一位Python的狂热爱好者,长期专注在测试开发与移动端自动化领域。崇尚开源与敏捷模式。闲暇时,爱好单车、读书、睡觉。他觉得这些都可以为他开拓眼界。

Dr. Philip Polstra(熟悉他的人都称呼他Dr. Phil),国际知名黑客。他的作品曾在许多国际的专题会议(包括DEFCON、Black Hat、44CON、Maker Faire等)上提及,发表过大量的论文,是这一领域公认的专家。

Dr. Polstra作为布鲁斯伯格大学的副教授,除了日常教学,还对外提供一些关于渗透测试的培训、咨询工作。

Walt Stoneburner,软件架构师,在商业应用开发与咨询领域有着25年以上的经验,另外在软件质量保证、配置管理与安全领域也有着长期的研究。

无论是在程序设计、协作应用、大数据、知识管理、数据可视化,还是在ASCII方面,他都有着很深的造诣。甚至在软件评测、消费电子产品测评、绘画、经营摄影工作室、创作幽默剧、游戏开发、无线电等领域都能找到他的身影,他还自称“极客”。

Yuri Weinstein,生活在旧金山,有超过20年的时间就职于硅谷顶尖的技术公司,专注测试领域,尤其是在自动化测试方向。目前在红帽公司负责Ceph开源存储项目的产品质量。


Selenium是一个主要用于Web应用程序自动化测试的工具集合,在行业内已经得到广泛的应用。然而其作用不局限于测试领域,还可以用于屏幕抓取与浏览器行为模拟等操作。它支持主流的浏览器,包括Firefox、IE、Chrome、Safari以及Opera等。

Selenium包括一系列的工具组件。

正如书名所述,这是一本介绍如何用Python语言调用Selenium WebDriver接口,进而实现对Web应用自动化测试的指导书。本书描述了从Selenium安装配置到基本使用,再到创建、调试、运行自动化脚本等进阶的操作。当然在开始之前,你可能需要先具备一定的Python语言基础。

第1章基于Python的Selenium WebDriver入门 从安装Python、Selenium WebDriver开始,到我们如何选择适合的Python编辑器,以及我们小试牛刀的第一个自动化测试脚本,并且成功地将这一脚本运行在不同浏览器上。

第2章使用unittest编写单元测试 本章带领我们结合unittest实现单元测试。通过转换后的脚本,有助于我们更好地完善单元测试用例。借助unittest实现测试用例集的整体运行,并将HTML格式的测试结果及时推送给项目的相关人员。

第3章元素定位 本章告诉你如何通过浏览器自带的开发者模式去定位页面中各类型元素。Selenium通过获取这些元素的定位,进而实现模拟浏览器操作与参数捕获。这一章你将学会各种定位元素的方法,包括XPath和CSS以及对应的示例。

第4章Selenium Python API介绍 学习如何通过WebDriver与包括页面元素、JavaScript 提示框、框架(frames)、窗口在内的各类对象进行交互,以及怎样进行浏览器回放、元素传值、鼠标点击、下拉菜单选择、多窗口切换等具体操作。

第5章元素等待机制 介绍多种设置等待方法,用于提高Selenium自动化测试脚本的稳定运行。带你理解显式等待或隐式等待的方法是如何应用于我们的测试脚本。

第6章跨浏览器测试 我们将深入学习如何在远程机器或Selenium Grid上通过Remote WebDriver实现测试脚本跨各类型浏览器的测试。Selenium Grid可使得我们在多浏览器与多操作系统的排列组合中兼容测试,甚至支持像PhantomJS这样的无UI界面的浏览器。本章的最后,我们还将了解Sauce Labs 和BrowserStack等第三方外部测试服务(云测试)。

第7章移动端测试 我们使用Selenium WebDriver、Appium实现在包括iOS端、Android端以及Android模拟器在内的移动设备上的自动化测试。另外,本章还有App测试的具体示例。

第8章Page Object与数据驱动测试 介绍这两种重要的设计模式,引导我们搭建更持续、更高效的测试框架。其中,Page Object设计模式可帮助我们实现对界面细节的封装,并将一组用户行为构建在单个类中,提升自动化测试脚本的易读性和可复用性,从而达到更适应UI的频繁变化的目的。另外,我们还将学习用unittest实现数据驱动测试。

第9章Selenium WebDriver的高级特性 包括复杂的鼠标与键盘操作、cookies操作、窗口截屏,甚至录制整个测试过程。

第10章第三方工具与框架集成 通过Selenium与持续集成工具的搭配,我们可以轻松地搭建自动化验收测试框架。本章中展示了“通过Selenium创建自动化验收测试用例,然后细化基于UI的自动化测试脚本,最后配置持续集成工具Jenkins,最终实现了对被测程序每日构建、每日自动化验收测试的联动效果”的典型案例。

通过对本书的学习,你将能够用Python语言通过调用Selenium WebDriver接口,搭建属于你自己的Web应用自动化测试框架。

在阅读本书之前,你需要掌握Python语言基本语法以及Web前端的相关知识(如HTML、JavaScript、CSS和XML)。如果你能编写一些简单的包括循环、条件判断、定义类等语法的Python脚本,你就能轻松地理解本书中的示例代码。每行示例代码我们都花了很大精力去注释说明,就是希望你能达到最佳的学习效果。还有一些前期准备的软件、工具以及环境配置都在第1章有明确的说明,你需要在你的机器上准备好访问终端、Python解释器以及浏览器。

如果你从事QA或软件测试、软件开发、Web应用开发等相关工作,希望用Python语言调用Selenium WebDriver,以实现对Web应用的自动化测试,那么这本书一定是你较好的选择!在学习Selenium理论之前,我们建议你掌握Python语言的基本语法。通过整本书的通篇学习,你将全面地理解Selenium WebDriver的相关知识,并且能有效地帮助你实现自动化测试。

本书中,你可能会发现不同类型的信息,呈现出的文本风格不尽相同。我们在这里将罗列不同类型的文本风格以及对应的含义,方便你阅读。

代码文本的样式如下。

# create a new Firefox session 
driver = webdriver.Firefox() 
driver.implicitly_wait(30) 
driver.maximize_window()

当我们想格外强调代码中的一部分时,相应的代码字体会被加粗,示例如下。

# run the suite
xmlrunner.XMLTestRunner(verbosity=2,output='test-reports').
 run(smoke_tests)

命令行的输入\输出的样式如下。

pip install -U selenium

新的措辞与关键语句会被显示为粗体。关键语句就是指出现在系统界面、菜单项或对话框等位置的关键操作,例如,“在Tools下拉菜单中选择Internet Options”。

 

警告或重要的提示,会出现在这样的括号中。

 

 

提醒或小窍门,会出现在这样的括号中。

我们十分乐见读者的反馈,让我们了解你对本书的想法——包括好与不好的评价。因为你的反馈将使我们以后可以更好地为读者提供有价值的内容。

可以通过我们的邮箱地址contact@epubit.com.cn将你的反馈信息告诉我们,邮件的主题需要注明书籍的全名。

当然,如果你也有专注的主题,并且有兴趣编辑或撰写图书,欢迎你联系我们,邮箱为zhangtao@ptpress.com.cn。


Selenium可以自动地操纵浏览器来做很多事情,它可以模拟我们与浏览器的交互,比如,访问网站,单击链接,填写表单,提交表单,浏览网页等,而且支持大多数主流的浏览器。如果要使用Selenium WebDriver,我们首先要选择一种语言来编写自动化脚本,而这个编程语言需要有Selenium client library支持。

本书中,我们将使用支持Selenium client library的Python语言来编写自动化脚本。Python是一门被广泛应用的高级编程语言,它是非常容易上手的,而且它的语法使我们只需要简短的代码就可以用来表达思想。Python设计的初衷就非常强调代码的可读性,它的基础架构使我们可以很方便地写无论大段的还是很少的程序代码,还提供大量的内置库、函数以及用户编写的第三方库,从而能够很容易地实现一些复杂的功能。

基于Python的Selenium WebDriver client library实现了所有Selenium WebDriver特性,而且能够通过Selenium standalone server来远程地和分布式地测试B/S项目。Selenium language bindings的开发者包含David Burns,Adam Goucher,Maik Röder,Jason Huggins,Luke Semerau,Miki Tebeka和Eric Allenin。

Selenium WebDriver client library 支持以下Python版本:2.6,2.7,3.2和3.3。

本章将介绍基于Python的Selenium WebDriver client library的安装步骤、基本特性和总体架构。

本章包括以下主题:

作为学习使用基于Python的Selenium的第一步,我们需要在计算机上安装好需要的软件。在下面的章节中让我们一步步来配置所需的基础环境。

在安装有Linux系统、Mac OS X系统和其他UNIX系统的计算机上,Python是系统默认安装好的。对于Windows系统,就需要另外单独安装Python了。基于不同平台的Python安装程序都可以在以下网站找到:http://python.org/download/。

 

本书所有的例子都是基于Python 2.7和Python 3.0编写,并在Windows 8 系统上经过测试的。

Selenium安装包里包含了Selenium WebDriver Python client library。为了使安装Selenium 包更简单,可以用pip安装工具:https://pip.pypa.io/en/latest/。

使用pip,可以非常简单地通过下面的命令来安装和更新Selenium安装包。

pip install -U selenium

安装过程非常简单。该命令将会安装Selenium WebDriver client library在计算机上,包含我们使用Python来编写自动化脚本需要的所有模块和类。pip工具将会下载最新版本的Selenium安装包并安装在计算机上。这个可选的 -U 参数将会更新已经安装的旧版本至最新版。

也可以从网站下载最新版本的Selenium安装包:https://pypi.python.org/pypi/selenium。在页面的右上角单击下载按钮,下载后解压文件,然后通过下面的命令来安装。

python setup.py install

Selenium WebDriver Python client library 文档可以从以下网址查看。

http://selenium.googlecode.com/git/docs/api/py/api.html

下面是截图。

这里提供了Selenium WebDriver的所有核心类和函数的详细信息。对于以下链接中的Selenium文档也要多加关注。

现在已经安装好了Python和Selenium WebDriver,还需要一个代码编辑器(IDE)来编写自动化脚本。一个好的IDE能够帮助我们提高产出,而且还能做一些其他的事情让编码变得简单。当我们用简单的编辑器来编写Python代码,比如Emacs、Vim或Notepad,用编辑器会让事情变得简单多了。其实有很多的IDE可供选择。一般来说,一款好的IDE能够通过以下一些特性帮忙开发者提高开发速度并节省编码时间:

如果你是个Python开发新手,或者是第一次接触Python的测试工程师,你的研发同事们能够帮助你安装和配置相应的IDE。

然而,如果你是第一次接触Python而不知道选择哪个IDE,这里有些建议可以帮助你做出选择。

1.1.4.1 PyCharm

PyCharm是JetBrains公司出品的软件,该公司是专业的软件开发工具的引领者,产品包含大家熟知的IntelliJ IDEA、RubyMine、PhpStorm和TeamCity。

PyCharm是一款设计精巧、功能强大、应用广泛而且工作良好的IDE。它继承了JetBrains 公司其他产品的一贯经验,拥有很多能够提升软件开发效率的特性。

PyCharm支持Windows系统、Linux系统和Mac系统。要想知道更多PyCharm的特性,可以访问以下网址:http://www.jetbrains.com/pycharm/

PyCharm有两种版本——社区版和专业版。社区版是免费的,而专业版是需要付费的。下面是PyCharm社区版运行一个简单Selenium脚本例子的截图。

社区版能够很好地构建和运行Selenium脚本,并提供调试支持。在本书后面的章节将会使用PyCharm。本章后面的部分,我们一步步来安装PyCharm,并用它来创建第一个Selenium脚本。

 

本书中所有的例子都是用PyCharm构建的,不过读者也可以很容易地应用别的IDE来构建这些例子。

1.1.4.2 PyDev Eclipse plugin

PyDev Eclipse plugin是另一款在Python开发者中应用广泛的代码编辑器。Eclipse是一款知名的开源代码编辑器,主要应用于构建Java程序,它通过插件式架构设计从而实现对其他多种编程语言的支持。

Eclipse是一款跨平台的IDE,支持Windows系统、Linux系统和Mac系统。可以在以下网址获取Eclipse的最新版本:http://www.eclipse.org/downloads

PyDev plugin需要在安装完Eclipse后单独安装。可以按照Lars Vogel编写的安装指南来安装PyDev:http://www.vogella.com/tutorials/Python/article.html。也可以在以下网址查看安装说明:http://pydev.org/。

下面是使用PyDev Eclipse plugin 运行一个简单Selenium脚本例子的截图。

1.1.4.3 PyScripter

对于Windows系统的用户,PyScripter也是一个很好的选择。它是一款开源的、轻量级的IDE。PyScripter像其他流行的IDE一样具有代码编译和代码自动补全的特性,并且提供测试和调试功能支持。可以从以下网站下载该软件并获取更多的信息:https://code.google.com/ p/pyscripter/。

下面是在 PyScripter上运行一个简单 Selenium 脚本实例的截图。

我们看过这些可选择的IDE后,回到PyCharm的设置。本书中所有的例子脚本都是通过PyCharm创建的,不过读者也可以使用其他IDE来创建并运行这些实例。下面将通过以下步骤来设置PyCharm,开始我们的Selenium Python之旅。

(1)从JetBrains官网下载和安装PyCharm。

(2)启动PyCharm社区版,在启动页面上单击Create New Project选项。

(3)在Create New Project对话框,参考下面的截图,在Project name文本框内输入工程名称。在本例中,setests作为工程名称。第一次运行PyCharm还需要配置解释器。单击Interpreter右侧的按钮来配置解释器。

(4)在弹出的Python Interpret对话框中,单击加号,PyCharm会显示出已经安装好的解释器路径。从Select Interpreter Path选择对应的解释器。

(5)PyCharm 将会配置好刚才选择的解释器。在Packages选项卡会显示Python安装包内自带的一些工具包。单击Apply按钮,然后单击OK按钮。

(6)返回到Create New Project对话框,单击OK按钮,项目创建成功。

 

我们也可以在命令行中运行脚本。打开命令行工具,切换到setests项目所在的目录中,运行以下命令:

在本书后面部分,我们更喜欢选择使用命令行方式去执行测试脚本。

我们现在可以开始创建和运行自动化测试脚本了。就从Selenium WebDriver开始,然后创建一个Python脚本,用Selenium WebDriver提供的类和方法模拟用户与浏览器的交互。

我们会使用一个简单的Web应用程序(本书上大多数例子都是基于这个应用程序)。这个简单的Web应用程序是基于一个著名电子商务框架Magento构建的。你可以在以下网址里找到这个应用程序:http://demo.magentocommerce.com/。

python searchproducts.py

 

示例代码下载 

如果你是在http://packtpub.com购买本书,你可以通过你的账号在该网址上下载示例代码文件。如果你是从其他地方购买本书,你可以访问http://www.packtpub.com/support并注册,我们会把示例代码文件直接发送到你的邮箱中。

示例代码也被托管在github中,访问地址为:https://github.com/upgundecha/learnsewithpython。

在这个简单的脚本中,我们会通过接下来的步骤去访问这个应用程序,搜索产品并在搜索结果页面中列出产品的名称。

(1)我们使用早前在部署PyCharm环境时创建的项目。创建一个引用了Selenium WebDriver client library的Python脚本。在项目资源管理器视图中,右击setests,在弹出的菜单中依次选择New→Python File

(2)在New Python file对话框中,在文件名文本框中输入“searchproducts”,然后单击OK按钮。

(3)PyCharm会在代码编写区域增加一个名为searchproducts.py的新页签。复制下列代码到searchproducts.py中。

from selenium import webdriver

# create a new Firefox session 
driver = webdriver.Firefox() 
driver.implicitly_wait(30) 
driver.maximize_window()

# navigate to the application home page 
driver.get("http://demo.magentocommerce.com/")

# get the search textbox
search_field = driver.find_element_by_name("q") 
search_field.clear()

# enter search keyword and submit 
search_field.send_keys("phones") 
search_field.submit()

# get all the anchor elements which have product names displayed
# currently on result page using find_elements_by_xpath method 
products = driver.find_elements_by_xpath("//h2[@class='product-name']/a")

# get the number of anchor elements found
print "Found " + str(len(products)) + " products:"

# iterate through each anchor element and print the text that is
# name of the product
for product in products: 
  print product.text 

# close the browser window 
driver.quit()

 

如果你使用的是其他IDE编译工具,请同样创建一个新的文件,复制代码到文件中并保存为searchproducts.py。

(4)可以通过以下方式运行脚本:在PyCharm代码窗口中使用快捷键Ctrl + Shift+ F10或者在Run菜单中选择Run 'searchproducts'命令。脚本开始执行,你会看到新弹出一个Firefox浏览器窗口访问演示网址,接着在Firefox浏览器窗口中会看到被执行的Selenium命令。如果一切运行顺利,最后脚本会关闭Firefox浏览器窗口。如下图所示,这个脚本会在PyCharm的控制台中打印产品的清单。

接下来,我们将会花点时间分析刚才创建的脚本。我们分析每个语句,初步地认识Selenium WebDriver。在本书的后面部分还有很多这样的分析。

Selenium.webdriver模块实现了Selenium所支持的各种浏览器驱动程序类,包括Firefox浏览器、Chrome浏览器、IE浏览器、Safari浏览器和多种其他浏览器。另外,RemoteWebDriver则是用于调用远程机器进行浏览器测试的。

我们需要从Selenium包中导入WebDriver才能使用Selenium WebDriver方法。

from selenium import webdriver

接着,我们还需要选用一个浏览器驱动实例,它会提供一个接口去调用Selenium命令来跟浏览器交互。在这个例子中,我们使用的是Firefox浏览器。我们可以通过下方命令来创建一个Firefox浏览器驱动实例。

driver = webdriver.Firefox()

在运行期间,这会加载一个新的Firefox浏览器窗口。我们也可以在这个驱动上设置一些参数,如:

driver.implicityly_wait(30)
driver.maximize_window()

我们使用30秒隐式等待时间来定义Selenium执行步骤的超时时间,并且调用Selenium API来最大化浏览器窗口。我们会在第5章“元素等待机制”中学习更多关于隐式等待的内容。

接着,我们使用示例程序的URL作为参数,通过调用driver.get()方法访问该应用程序。在get()方法被调用后,WebDriver会等待,一直到页面加载完成才继续控制脚本。

在加载页面后,Selenium会像用户真实使用那样,和页面上各种各样的元素交互。例如,在应用程序的主页,我们需要在输入框中输入一个搜索内容,然后单击Search按钮。这些元素作为HTML输入元素实现,Selenium需要找到这些元素来模拟用户操作。Selenium WebDriver提供多种方法来定位和操作这些元素,例如设置值,单击按钮,在下拉组件中选择选项等。我们可以在第3章“元素定位”中了解更多。

在这个例子中,我们使用find_element_by_name方法来定位搜索输入框。这个方法会返回第一个name属性值与输入参数匹配的元素。HTML元素是用标签和属性来定义的,我们可以使用这些信息来定位一个元素,步骤如下。

(1)在这个例子中,搜索输入框有一个值为q的name属性,我们使用这个属性来定位,代码如下。

search_field = driver.find_element_by_name("q")

(2)一旦找到这个搜索输入框,我们可以使用clear()方法来清理之前的值(如果搜索输入框已经有值的话),并且通过send_keys()方法输入新的特定的值。接着我们通过调用submit()方法提交搜索请求。

search_field.clear()
search_field.send_keys("phones")
search_field.submit()

(3)在提交搜索请求后,Firefox浏览器会加载结果页面。结果页面中有一系列与搜索项(phones)匹配的产品。我们可以读取结果列表,并且可以使用find_elements_by_xpath方法获取路径是以<a>标签结尾的所有产品名称。它将会返回多于1个的元素列表。

products = 
 driver.find_elements_by_xpath("//h2[@class=
 'product-name']/a")

(4)接着,我们打印在页面中展示的产品个数(即符合路径以<a>标签结尾的元素个数)和产品的名称(即<a>标签的text属性值)。

print "Found " + str(len(products)) + " products:"

for product in products:
  print product.text

(5)在脚本的最后,我们使用driver.quit()方法来关闭Firefox浏览器。

driver.quit()

这个例子直观地向我们展示如何使用Selenium WebDriver和Python配合来创建一个简单的自动化脚本。我们在这个脚本里面并没有测试什么。在本书后面的章节,我们将会扩展这个简单的脚本为一组测试脚本,并且会引用多个其他库和Python的功能。

目前我们已经在Firefox浏览器构建并运行了脚本。Selenium支持各种浏览器,读者可以在不同的浏览器中进行自动化测试。它支持的浏览器包括IE浏览器、Google Chrome浏览器、Safari浏览器、Opera浏览器,甚至是像PhantomJS这样的无UI界面的浏览器。接下来的部分,我们会修改刚才创建的脚本,以便在IE浏览器和Google Chrome浏览器中运行脚本,以此来验证Selenium WebDriver跨浏览器的兼容性。

在IE浏览器中运行脚本步骤会多一些。我们需要下载并安装InternetExplorerDriver。InternetExplorerDriver是一个独立的可执行的服务,它实现WebDriver的协议,使得WebDriver可以与测试脚本和IE浏览器交互。InternetExplorerDriver支持Windows XP、Vista、Windows 7和Windows 8操作系统下的主要IE版本。通过以下步骤安装InternetExplorerDriver。

(1)在http://www.seleniumhq.org/download/中下载InternetExplorerDriver服务。你可以根据自己的操作系统来选择下载32位或64位版本。

(2)在下载完成后,解压文件,并把文件复制到存储脚本的目录中。

(3)在IE 7及其以上版本,每个区域的保护模式设置一定要有相同的值。在每个区域中保护模式要么启用,要么关闭。设置保护模式的步骤如下。

① 在工具菜单下选择Internet选项。

② 在Internet选项对话框中,单击安全标签页。

③ 在“选择区域以查看或更改安全设置”中选择每一个区域,确定每个区域的保护模式的值保持一致(要么选中,要么不选中)。所有区域用相同的设置,如下图所示。

 

在使用InternetExplorerDriver时,注意保持浏览器缩放等级设置成100%,以此来保证鼠标的单击事件能点到正确的坐标。

(4)修改脚本使其支持IE浏览器。我们通过以下方式来使用IE替代Firefox实例。

import os
from selenium import webdriver

# get the path of IEDriverServer
dir = os.path.dirname(__file__)
ie_driver_path = dir + "\IEDriverServer.exe"

# create a new Internet Explorer session
driver = webdriver.Ie(ie_driver_path)
driver.implicitly_wait(30)
driver.maximize_window()

# navigate to the application home page
driver.get("http://demo.magentocommerce.com/")

# get the search textbox
search_field = driver.find_element_by_name("q")
search_field.clear()

# enter search keyword and submit
search_field.send_keys("phones")
search_field.submit()

# get all the anchor elements which have product names displayed
# currently on result page using find_elements_by_xpath method
products = driver.find_elements_by_xpath("//h2[@class='product-name']/a")

# get the number of anchor elements found
print "Found " + str(len(products)) + " products:"

# iterate through each anchor element and print the text that is 
# name of the product
for product in products:
  print product.text

# close the browser window
driver.quit()

在这个脚本中,在创建IE浏览器实例时,我们传递了InternetExplorerDriver的路径。

(5)运行脚本后,Selenium会加载InternetExplorerDriver服务,用它来启动浏览器和执行脚本。InternetExplorerDriver服务在Selenium脚本和浏览器之间扮演类似中介角色。实际执行的步骤与我们在Firefox浏览器观察的类似。

 

在https://code.google.com/p/selenium/wiki/

InternetExplorerDriver中可以获取更多关于IE的重要设置。

在https://code.google.com/p/selenium/wiki/

DesiredCapabilities 查阅DesiredCapabilities的文章。

在Google Chrome浏览器中设置和运行脚本的步骤与IE浏览器的相似。我们需要下载ChromeDriver服务。ChromeDriver服务是一个由Chromium team开发维护的独立的服务,它支持Windows操作系统、Linux操作系统和Mac操作系统。使用以下步骤来设置ChromeDriver服务。

(1)在http://chromedriver.storage.googleapis.com/index.html下载ChromeDriver服务。

(2)下载完ChromeDriver服务后,解压文件,并把文件复制到存储脚本的目录中。

(3)修改脚本使其支持Chrome浏览器。我们通过以下方式创建Chrome实例,用此来替换Firefox浏览器实例。

import os
from selenium import webdriver

# get the path of chromedriver
dir = os.path.dirname(__file__)
chrome_driver_path = dir + "\chromedriver.exe"
# remove the .exe extension on linux or mac platform

# create a new Chrome session
driver = webdriver.Chrome(chrome_driver_path)
driver.implicitly_wait(30)
driver.maximize_window()

# navigate to the application home page
driver.get("http://demo.magentocommerce.com/")

# get the search textbox
search_field = driver.find_element_by_name("q")
search_field.clear()

# enter search keyword and submit
search_field.send_keys("phones")
search_field.submit()

# get all the anchor elements which have product names displayed
# currently on result page using find_elements_by_xpath method
products = driver.find_elements_by_xpath("//h2[@class='product-name']/a")

# get the number of anchor elements found
print "Found " + str(len(products)) + " products: "

# iterate through each anchor element and print the text that is 
# name of the product
for product in products:
  print product.text

# close the browser window
driver.quit()

在这个脚本中,在创建Chrome浏览器实例时,我们传递了ChromeDriver的路径。

(4)运行脚本后,Selenium会加载ChromeDriver服务,用它来启动浏览器和执行脚本。

实际执行的步骤与我们在Firefox浏览器观察的类似。

 

想了解更多关于ChromeDriver,请访问https://code.google.com/p/selenium/ wiki/ChromeDriver和https://sites.google.com/a/chromium.org/chromedriver/ home。

在本章中,我们介绍了Selenium和它的组件。通过pip工具安装了Selenium包。接着介绍了多个用于编写Selenium和Python代码的编辑器和IDE工具,部署了PyCharm环境。然后我们通过创建基于示例程序的测试脚本,成功运行在Firefox浏览器,并分析了整个过程。最后,我们举一反三(分别在IE浏览器和Chrome浏览器中配置和运行脚本)来验证Selenium WebDriver的跨浏览器的特性。

在下一章,我们将学习如何通过Selenium WebDriver使用unittest库来创建自动化单元测试。我们也将学习如何创建并运行一组测试脚本。


Selenium WebDriver是一个浏览器自动化测试的API集合。它提供了很多与浏览器自动化交互的特性,并且这些API主要是用于测试Web程序。如果仅仅使用Selenium WebDriver,我们无法实现执行测试前置条件、测试后置条件,比对预期结果和实际结果,检查程序的状态,生成测试报告,创建数据驱动的测试等功能。在本章,我们将学习如何使用unittest来创建基于Python的Selenium WebDriver测试脚本。

本章包含以下主题:

unittest(一般称为PyUnit)是从Java程序开发中广泛应用的JUnit启发而来的。我们可以使用unittest为任何项目创建全面的测试套件。unittest也是Python中用来测试各种标准类库模块的,甚至包括unittest自己。可以在以下网址查看unittest的文档:http://docs.python.org/2/library/unittest.html。

unittest使我们具备创建测试用例、测试套件、测试夹具的能力。可以通过下面的图来了解所有的组件。

通过与unittest类似的xUnite测试框架创建的测试被拆分为3部分,即3A’s,具体如下。

我们在本章接下来的内容中将应用此方法来使用unittest创建测试。

 

我们将在本书接下来的部分使用unittest来创建和运行基于Selenium WebDriver的测试。另外,Python还有些具备额外特性的其他测试框架,例如:

 

  • Nose此框架扩展了unittest并且提供了自动搜索和运行测试的功能,也提供了一些插件来创建高级的测试。可以在以下网站查看关于Nose的更多信息。
    https://nose.readthedocs.org/en/latest/

  • PytestPytest是另外一个测试框架,它提供了一些基于Python来编写和运行单元测试的高级特性。可以在以下网站查看关于Pytest的更多信息。
    http://pytest.org/latest/

我们可以通过继承TestCase类并且在测试类中为每一个测试添加测试方法来创建单个测试或者一组测试。为了创建测试,我们需要使用TestCase类中的assert或者使用其中的一种assert方法。每个测试最重要的任务是调用assertEqual()来校验预期结果,调用assertTrue() 来验证条件,或者调用assertRaises() 来验证预期的异常。

除了添加测试,我们可以添加测试夹具——setUp()方法和tearDown()方法,创建或处置测试用例所需要的任何对象和条件。

让我们开始使用unittest,首先通过继承TestCase类然后添加一个测试方法,来为第1章(基于Python的Selenium WebDriver入门)中的例子脚本写一个简单的测试。

我们需要先引入unittest模块,然后定义一个继承于TestCase 类的子类,具体如下。

import unittest
from selenium import webdriver

class SearchTest (unittest.TestCase):

2.1.1.1 setUp()方法

一个测试用例是从setUp()方法开始执行的,我们可以用这个方法在每个测试开始前去执行一些初始化的任务。可以是这样的初始化准备:比如创建浏览器实例,访问URL,加载测试数据和打开日志文件等。

此方法没有参数,而且不返回任何值。当定义了一个setUp()方法,测试执行器在每次执行测试方法之前优先执行该方法。在下面的例子里,我们将用setUp()方法来创建Firefox的实例,设置properties,而且在测试开始执行之前访问到被测程序的主页。例子如下。

import unittest
from selenium import webdriver

class SearchTests(unittest.TestCase):
    def setUp(self):
        # create a new Firefox session
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.driver.maximize_window()

        # navigate to the application home page
        self.driver.get("http://demo.magentocommerce.com/")

2.1.1.2 编写测试

有了setUp()方法,现在可以写一些测试用来验证我们想要测试的程序的功能。在这个例子里,我们将搜索一个产品,然后检查是否返回一些相应的结果。与setUp()方法相似,test方法也是在TestCase类中实现。重要的一点是我们需要给测试方法命名为test开头。这种命名约定通知test runner哪个方法代表测试方法。

对于test runner能找到的每个测试方法,都会在执行测试方法之前先执行setUp()方法。这样做有助于确保每个测试方法都能够依赖相同的环境,无论类中有多少测试方法。我们将使用简单的assertEqual()方法来验证用程序搜索该术语返回的结果是否和预期结果相匹配。我们将在本章后面内容探讨更多关于断言的内容。

添加一个新的测试方法test_search_by_category(),通过分类来搜索产品,然后校验返回的产品的数量是否正确,具体如下。

import unittest
from selenium import webdriver

class SearchTests(unittest.TestCase):
    def setUp(self):
        # create a new Firefox session
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.driver.maximize_window()

        # navigate to the application home page
        self.driver.get("http://demo.magentocommerce.com/")

 def test_search_by_category(self):
 # get the search textbox
 self.search_field = self.driver.find_element_by_name("q")
 self.search_field.clear()

 # enter search keyword and submit
 self.search_field.send_keys("phones")
 self.search_field.submit()

 # get all the anchor elements which have product names
 # displayed currently on result page using
 # find_elements_by_xpath method
 products = self.driver.find_elements_by_xpath
 ("//h2[@class='product-name']/a")
 self.assertEqual(2, len(products))

2.1.1.3 代码清理

类似于setUp()方法在每个测试方法之前被调用,TestCase类也会在测试执行完成之后调用tearDown()方法来清理所有的初始化值。一旦测试被执行,在setUp()方法中定义的值将不再需要,所以最好的做法是在测试执行完成的时候清理掉由setUp()方法初始化的数值。在我们的例子里,在测试执行完成后,就不再需要Firefox的实例。我们将在tearDown()方法中关闭Firefox实例,如下代码所示。

import unittest
from selenium import webdriver

class SearchTests(unittest.TestCase):
    def setUp(self):
        # create a new Firefox session
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.driver.maximize_window()

        # navigate to the application home page
        self.driver.get("http://demo.magentocommerce.com/")

    def test_search_by_category(self):
        # get the search textbox
        self.search_field = self.driver.find_element_by_name("q")
        self.search_field.clear()

        # enter search keyword and submit
        self.search_field.send_keys("phones")
        self.search_field.submit()

        # get all the anchor elements which have product names
        # displayed currently on result page using
        # find_elements_by_xpath method
        products = self.driver.find_elements_by_xpath
          ("//h2[@class='product-name']/a")
        self.assertEqual(2, len(products))

 def tearDown(self):
 # close the browser window
 self.driver.quit()

2.1.1.4 运行测试

为了通过命令行运行测试,我们可以在测试用例中添加对main方法的调用。我们将传递verbosity参数以便使详细的测试总量展示在控制台。

if __name__ == '__main__':
    unittest.main(verbosity=2)

我们可以把测试脚本保存为普通的Python脚本。在这个例子里,把测试保存为searchtests.py。保存文件以后,我们可以通过下面的命令行来执行该测试。

python searchtests.py

测试运行结束后,unittest会把测试结果和概要展示在控制台,如下图所示。

除了测试结果概要外,当一个测试用例执行失败,针对每个失败,测试结果概要都会通过生成文本信息来展示具体哪里有错误。通过下面的截图,可以看到当我们修改预期结果值后会发生些什么。

上图展示了具体是哪个测试方法执行失败,通过打印信息可以追踪具体导致失败的代码。另外,失败自身也会以AssertionError形式显示,例子中的预期结果和实际结果并不匹配。

2.1.1.5 添加其他测试

我们可以用一组测试来构建一个测试类,这样有助于为一个特定功能创建一组更合乎逻辑的测试。下面为测试类添加其他的测试。规则很简单,新的测试方法命名也要以test开头,如下列代码。

def test_search_by_name(self):
        # get the search textbox
        self.search_field = self.driver.find_element_by_name("q")
        self.search_field.clear()

        # enter search keyword and submit
        self.search_field.send_keys("salt shaker")
        self.search_field.submit()

        # get all the anchor elements which have
        # product names displayed
        # currently on result page using
        # find_elements_by_xpath method
        products = self.driver.find_elements_by_xpath
          ("//h2[@class='product-name']/a")
        self.assertEqual(1, len(products))

运行这个测试类将能看到两个Firefox的实例打开和关闭,这正是setUp()方法和tearDown()方法针对每个测试方法都要执行产生的结果,如下图所示。

在前面的例子中,我们通过setUp()方法为每个测试方法都创建了一个Firefox实例,并且在每个测试方法执行结束后都要关闭实例。能否让各个测试方法共用一个Firefox实例,而不要每次都创建一个新的实例呢?这可以通过使用setUpClass()方法和tearDownClass()方法及@classmethod标识来实现。这两个方法使我们可以在类级别来初始化数据,替代了方法级别的初始化,这样各个测试方法就可以共享这些初始化数据。在下面的例子中,代码修改为调用setUpClass()方法和tearDownClass()方法并且加上@classmethod标识。

import unittest
from selenium import webdriver

class SearchTests(unittest.TestCase):
 @classmethod
 def setUpClass(cls):
 # create a new Firefox session
 cls.driver = webdriver.Firefox()
 cls.driver.implicitly_wait(30)
 cls.driver.maximize_window()

 # navigate to the application home page
 cls.driver.get("http://demo.magentocommerce.com/")
 cls.driver.title

 def test_search_by_category(self):
       # get the search textbox
       self.search_field = self.driver.find_element_by_name("q")
        self.search_field.clear()

        # enter search keyword and submit
        self.search_field.send_keys("phones")
        self.search_field.submit()

        # get all the anchor elements which have product names
     # displayed currently on result page using
     # find_elements_by_xpath method
    products = self.driver.find_elements_by_xpath
          ("//h2[@class='product-name']/a")
    self.assertEqual(2, len(products))

 def test_search_by_name(self):
     # get the search textbox
     self.search_field = self.driver.find_element_by_name("q")
     self.search_field.clear()
 
     # enter search keyword and submit
     self.search_field.send_keys("salt shaker")
     self.search_field.submit()
 
     # get all the anchor elements which have product names
     # displayed currently on result page using
     # find_elements_by_xpath method
     products = self.driver.find_elements_by_xpath
          ("//h2[@class='product-name']/a")
     self.assertEqual(1, len(products))

 @classmethod
 def tearDownClass(cls):
 # close the browser window
 cls.driver.quit()

 if __name__ == '__main__':
 unittest.main()

运行这个测试将看到仅创建一个Firefox实例,所有的测试都用同一个实例。

 

要了解更多关于@classmethod标识的信息,参考:https://docs.python.org/2/library/ functions.html#classmethod。

unittest的TestCase类提供了很多实用的方法来校验预期结果和程序返回的实际结果是否一致。这些方法要求必须满足某些条件才能继续执行接下来的测试。大致有3种这样的方法,各覆盖一个特定类型的条件,例如等价校验、逻辑校验和异常校验。如果给定的断言通过了,接下来的测试代码将会执行;相反,将会导致测试立即停止并且给出异常信息。

unittest提供了所有的标准xUnit 断言方法。下表列出了一些在本书后面将要用到的重要方法。

方  法 校 验 条 件 应 用 实 例
assertEqual(a, b [,msg]) a == b 这些方法校验a和b是否相等,msg对象是用来说明失败原因的消息。
这对于验证元素的值和属性等是非常有用的。例如:
assertEqual(element.text, "10")
assertNotEqual(a,
b[,msg])
a != b
assertTrue(x[,msg])) bool(x) is True 这些方法校验给出的表达式是True还是False。
例如,校验一个元素是否出现在页面,我们可以用下面的方法:
assertTrue(element.is_displayed())
assertFalse(x[,msg])) bool(x) is False
assertIsNot(a, b[,msg])) a is not b
assertRaises(exc, fun,
*args, **kwds)
fun(*args, **kwds) raises exc 这些方法校验特定的异常是否被具体的测试步骤抛出,用到该方法的一种可能情况是:
NoSuchElementFoundexception
assertRaisesRegexp(exc,
r, fun, *args, **kwds)
fun(*args,**kwds) raises exc and the message matches regex r
assertAlmostEqual(a, b) round(a-b, 7) == 0 这些方法用于检查数值,在检查之前会按照给定的精度把数字四舍五入。这有助于统计由于四舍五入产生的错误和其他由于浮点运算产生的问题
assertNotAlmostEqual(a,
b)
round(a-b, 7) != 0
assertGreater(a, b) a > b 这些方法类似于assertEqual()方法,是为逻辑判定条件设计的
assertGreaterEqual(a, b) a >= b
assertLess(a, b) a < b
assertLessEqual(a, b) a <= b
assertRegexpMatches(s, r) r.search(s) 这些方法检查文本是否符合正则匹配
assertNotRegexpMatches(s, r) not r.search(s)
assertMultiLineEqual(a, b) strings 此方法是assertEqual()的一种特殊形式,为多行字符串设计。等值校验和其他单行字符串校验一样,但是默认失败信息经过优化以后可以展示具体值之间的差别
assertListEqual(a, b) lists 此方法校验两个list是否相等,对于下拉列表选项字段的校验是非常有用的
fail() 此方法是无条件的失败。在别的assert方法不好用的时候,也可用此方法来创建定制的条件块

应用unittest的TestSuites特性,可以将不同的测试组成一个逻辑组,然后设置统一的测试套件,并通过一个命令来执行测试。这都是通过TestSuites、TestLoader和TestRunner类来实现的。

在了解TestSuites的细节之前,我们为例子程序添加一个新的测试,用于校验主页。我们将把新加的测试和之前的测试放到一个测试组件中,详见下面代码。

import unittest
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
from __builtin__ import classmethod

class HomePageTest(unittest.TestCase):
    @classmethod
    def setUp(cls):
        # create a new Firefox session """
        cls.driver = webdriver.Firefox()
        cls.driver.implicitly_wait(30)
        cls.driver.maximize_window()
        # navigate to the application home page """
        cls.driver.get("http://demo.magentocommerce.com/")

    def test_search_field(self):
        # check search field exists on Home page
        self.assertTrue(self.is_element_present(By.NAME,"q"))

    def test_language_option(self):
        # check language options dropdown on Home page
        self.assertTrue(self.is_element_present
          (By.ID,"select-language"))

    def test_shopping_cart_empty_message(self):
        # check content of My Shopping Cart block on Home page
        shopping_cart_icon = \ 
            self.driver.find_element_by_css_selector
              ("div.header-minicart span.icon")
        shopping_cart_icon.click()

        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_button =  self.driver.find_element_by_css_selector
          ("div.minicart-wrapper a.close")
        close_button.click()

    @classmethod
    def tearDown(cls):
        # close the browser window
        cls.driver.quit()

    def is_element_present(self, how, what):
        """
        Utility method to check presence of an element on page
        :params how: By locator type
        :params what: locator value
        """
        try: self.driver.find_element(by=how, value=what)
        except NoSuchElementException, e: return False
        return True

    if __name__ == '__main__':
        unittest.main(verbosity=2)

我们将用TestSuite类来定义和执行测试套件。我们可以把多个测试加入到一个测试套件中去。除了TestSuite类,我们还可以用TestLoader和TextTestRunner来创建和运行测试套件,举例如下。

import unittest
from searchtests import SearchTests
from homepagetests import HomePageTest

# get all tests from SearchProductTest and HomePageTest class
search_tests = unittest.TestLoader().loadTestsFromTestCase
(SearchTests)
home_page_tests = unittest.TestLoader().loadTestsFromTestCase
(HomePageTest)

# create a test suite combining search_test and home_page_test
smoke_tests = unittest.TestSuite([home_page_tests, search_tests])

# run the suite
unittest.TextTestRunner(verbosity=2).run(smoke_tests)

使用TestLoader类,我们将得到指定测试文件中的所有测试方法且用于创建测试套件。TestRunner类将通过调用测试套件来执行文件中所有的测试。

我们可以通过下面的命令运行新的测试套件文件。

python smoketests.py

这将运行SearchProductTest类和HomePageTest类中的所有测试并且通过命令行形式生成下图这样的测试输出。

unittest在命令行输出测试结果。你可能需要生成一个所有测试的执行结果作为报告或者把测试结果发给相关人员。给相关人员发送命令行日志不是一个明智的选择。他们需要格式更加友好的测试报告,既能够查看测试结果的概况,也能够深入查看报告细节。unittest没有相应的内置模块可以生成格式友好的报告,我们可以应用Wai Yip Tung编写的unittest的扩展HTMLTestRunner来实现。从下面的网址可以获取更多关于HTMLTestRunner的信息并可以下载说明文档:https://pypi.python.org/pypi/HTMLTestRunner。

 

HTMLTestRunner扩展可以在本书的附件源代码中找到。

我们将在测试中使用HTMLTestRunner来生成漂亮的测试报告。通过修改在本章前面涉及的测试套件文件来添加HTMLTestRunner支持。我们需要创建一个包含实际测试报告的输出文件,需要配置HTMLTestRunner选项和运行测试,具体如下。

import unittest
import HTMLTestRunner
import os
from searchtests import SearchTests
from homepagetests import HomePageTest

# get the directory path to output report file
dir = os.getcwd()

# get all tests from SearchProductTest and HomePageTest class
search_tests = unittest.TestLoader().loadTestsFromTestCase(SearchTests)
home_page_tests = unittest.TestLoader().loadTestsFromTestCase(HomePageTest)

# create a test suite combining search_test and home_page_test
smoke_tests = unittest.TestSuite([home_page_tests, search_tests])

# open the report file
outfile = open(dir + "\SmokeTestReport.html", "w")

# configure HTMLTestRunner options
runner = HTMLTestRunner.HTMLTestRunner(
                 stream=outfile,
                 title='Test Report',
                 description='Smoke Tests'
                 )

# run the suite using HTMLTestRunner
runner.run(smoke_tests)

执行该测试套件,HTMLTestRunner像unittest的默认测试执行器一样运行所有的测试。在用例执行的最后,它将生成测试报告文件,如下图所示。

本章我们学习了如何使用unittest来编写和运行基于Selenium WebDriver的测试脚本。我们使用包含setUp()方法和tearDown()方法的TestCase类来创建测试。我们还可以添加断言来验证预期结果和实际结果是否一致。

我们也学习了如何使用unittest支持的不同类型的断言。我们实现了测试套件,它提供了把不同的测试用例组成逻辑分组的能力。最后,我们使用HTMLTestRunner来生成格式友好的HTML格式的测试报告。

在下一章中,我们将学习如何定义和使用定位器来与页面中的不同类型的HTML元素进行交互。


Web应用以及包含超文本标记语言(HTML)层叠样式表(CSS)、JavaScript脚本的Web页面;基于用户的操作行为诸如跳转到指定的统一资源定位(URL)网站,或是单击提交按钮,浏览器向Web服务器发送请求;Web服务器响应请求,返回给浏览器HTML以及相关的JavaScript、CSS、图片等资源;浏览器使用这些资源生成Web页面,其中包含Web各种视觉元素,例如文本框、按钮、标签页、图表、复选框、单选按钮、列表、图片等。上面列举的这些,我们普通用户并不用关心,放心交给HTML去组织并且最终呈现在浏览器里即可。这些视觉元素或控件都被Selenium称为页面元素(WebElements)

本章包含以下主题:

当我们想让Selenium自动地操作我们的浏览器,就必须告诉Selenium如何去定位某个元素或一组元素,可以通过编程的方式去模拟用户操作。每个元素有着不同的标签名和属性值,Selenium提供了多种选择与定位元素的方法。

我们如何获取这些信息呢?大家都知道,Web页面是由HTML、CSS和JavaScript等组成的。我们可以通过查看页面源文件的方式了解这些文本信息,进而可以找到我们想要的tag标签,了解与之对应的元素是如何交互的、如何定义属性与属性值的,以及页面的结构。下面展示了一个我们正在测试的场景,这是一个常见的搜索功能,包括搜索框与搜索按钮(放大镜图标)。

让我们看一下其对应的HTML脚本。

<form id="search_mini_form" action= 
 "http://demo.magentocommerce.com/catalogsearch/result/" 
 method="get">
   <div class="form-search">
     <label for="search">Search:</label>
     <input id="search" type="text" name="q" value="" 
      class="input-text" maxlength="128" />
     <button type="submit" title="Search" 
      class="button"><span><span>Search</span></span></button>
     <div id="search_autocomplete" class="search-
      autocomplete"></div>
     <script type="text/javascript"> 
     //<![CDATA[
       var searchForm = new Varien.searchForm 
        ('search_mini_form', 'search', 'Search entire store 
        here...');
       searchForm.initAutocomplete
        ('http://demo.magentocommerce.com
        /catalogsearch/ajax/suggest/', 
        'search_autocomplete');
     //]]>
     </script>
   </div>
</form>

我们发现类似搜索框、搜索按钮这样的元素,都是采用内嵌在<form>标签内的<input>标签来实现,标记则用了<label>标签来实现。另外,JavaScript代码写在了<script>标签内。

其中搜索框<input>标签中包含id、type、name、value、class和maxlength属性的定义。

<input id="search" type="text" name="q" value="" 
  class="input-text" maxlength="128" />

我们可以在浏览器窗口右键单击,在快捷菜单中选择查看源文件选项,在弹出的窗口中可以显示HTML文件与JavaScript脚本。

 

如果你对查看HTML、CSS和JavaScript感到生疏的话,可以查看相关网站,可以帮助你更快地识别WebDriver所需的元素的位置。

在使用Selenium测试之前,我们通常会先去查看页面源代码,借助工具可以帮助我们了解页面结构。值得庆幸的是,目前绝大多数的浏览器都内置有相关插件,能够快速、简洁地展示各类元素的属性定义、DOM结构、JavaScript代码块、CSS样式等属性。接下来我们一起学习这类工具的细节以及使用方法。

较新版本的火狐浏览器尽管自带有页面分析工具,然而,我们还是建议大家使用功能更强大的Firebug插件。

(1)你可以通过下列地址,下载并安装Firebug插件。

https://addons.mozilla.org/en-us/firefox/addon/firebug/

(2)尝试用Firebug,在页面上移动鼠标至希望获取的元素,然后右键单击,弹出快捷菜单。

(3)选择使用Firebug查看元素。此时火狐浏览器下方会显示HTML代码树窗口并定位到所选的元素上,如下图所示。

(4)我们还可以使用Firebug的XPath或CSS选择器,通过Firebug弹出窗口自带的检索功能,只要键入想要查找的关键字,就可以高亮显示与之匹配的元素,如下图所示。

谷歌Chrome浏览器也自带有页面分析的功能。你可以通过以下步骤来检查页面元素。

(1)首先移动鼠标光标到期望的元素上,然后右键单击,在弹出的快捷菜单中,选择检查(N)选项。

在浏览器的下方,将显示类似Firebug的开发者工具窗口,如下图所示。

(2)同样类似Firebug,当我们需要使用XPath或CSS选择器时,在开发者工具下的Elements窗口中,按Ctrl+F键,将会显示搜索框。一旦输入XPath或CSS表达式,Firebug就会高亮显示与之匹配的元素,如下图所示。

微软公司的IE浏览器也自带有页面分析的功能。你可以通过以下步骤来检查页面元素。

(1)按F12键,在浏览器下方显示开发者工具窗口。

(2)在开发者工具窗口选择“箭头”按钮,然后单击页面中期望获取的元素,在开发者工具窗口将高亮显示对应的HTML代码树,如下图所示。

通过上述工具,可以非常有效地帮助我们编写测试代码,以及执行与调试JavaScript脚本。

我们必须告诉Selenium怎样去定位元素,用来模拟用户动作,或者查看元素的属性和状态,以便我们可以执行检查。例如,我们要搜索一个产品,首先要找到搜索框与搜索按钮,接着通过键盘输入要查询的关键字,最后用鼠标单击搜索按钮,提交搜索请求。

正如上述人工的操作步骤一样,我们也希望Selenium能模拟我们的动作,然而,Selenium并不能理解类似在搜索框中输入关键字或单击搜索按钮这样图形化的操作。所以需要我们程序化地告诉Selenium如何定位搜索框与搜索按钮,从而模拟键盘与鼠标的动作。

Selenium提供多种find_element_by 方法用于定位页面元素。这些方法根据一定的标准去查找元素,如果元素被正常定位,那么WebElement实例将返回。反之,将抛出NoSuchElementException的异常。同时,Selenium还提供多种find_elements_by 方法去定位多个元素,这类方法根据所匹配的值,搜索并返回一个list数组(元素)。

Selenium提供8种find_element_by 方法用于定位元素。接下来的部分,我们将逐一介绍方法细节,如下表所示。

方  法

描  述

参  数

示  例

find_element_by_id(id)

通过元素的ID属性值来定位元素

id:元素的ID

driver.find_element_by_id('search')

find_element_by_name(name)

通过元素的name属性值来定位元素

name:元素的name

driver.find_element_by_name('q')

find_element_by_class_name(name)

通过元素的class名来定位元素

name:元素的类名

driver.find_element_by_class_name('input-text')

find_element_by_tag_name(name)

通过元素的tag name来定位元素

name:tag name

driver.find_element_by_tag_name('input')

find_element_by_xpath(xpath)

通过XPath来定位元素

XPath:元素的XPath

driver.find_element_by_xpath('//form[0]/div[0]/input[0]')

find_element_by_css_selector(css_selector)

通过CSS选择器来定位元素

css_selector:元素的CSS选择器

driver.find_element_by_css_selector('#search')

find_element_by_link_text(link_text)

通过元素标签对之间的文本信息来定位元素

link_text:文本信息

driver.find_element_by_link_text('Log In')

find_element_by_partial_link_text(link_text)

通过元素标签对之间的部分文本信息来定位元素

link_text:部分文本信息

driver.find_element_by_partial_link_text('Log')

find_elements_by 方法能按照一定的标准返回一组元素,具体见下表。

方  法

描  述

参  数

示  例

find_elements_by_id(id_)

通过元素的ID属性值来定位一组元素

id_:元素的ID

driver.find_elements_by_id('product')

find_elements_by_name(name)

通过元素的name属性值来定位一组元素

name:元素的name

driver.find_elements_by_name('products')

find_elements_by_class_name(name)

通过元素的class名来定位一组元素

name:元素的类名

driver.find_elements_by_class_name('foo')

find_elements_by_tag_name(name)

通过元素的tag name来定位一组元素

name:tag name

driver.find_elements_by_tag_name('a')

find_elements_by_xpath(xpath)

通过XPath来定位一组元素

XPath:元素的XPath

driver.find_elements_by_xpath("//div[contains(@class,'lists')]")

find_elements_by_css_selector(css_selector)

通过CSS选择器来定位一组元素

css_selector:元素的CSS选择器

driver.find_elements_by_css_selector('.input-class')

find_elements_by_link_text(text)

通过元素标签对之间的文本信息来定位一组元素

text:文本信息

driver.find_elements_by_link_text('Log In')

find_elements_by_partial_link_text(link_text)

通过元素标签对之间的部分文本信息来定位一组元素

link_text:部分文本信息

driver.find_elements_by_partial_link_text('Add to,')

通过ID查找元素是查找页面上元素的最佳方法。find_element_by_id()和find_elements_by_id()方法返回与ID属性值匹配的一个元素或一组元素。

find_element_by_id()方法返回的是与ID属性值匹配的第一元素,如果没有元素与之匹配,则抛出NoSuchElementException异常。

如下图所示,我们尝试来定位搜索框。

通过查看HTML,我们可以看到搜索框的ID值被定义为search。

<input id="search" type="text" name="q" value="" 
 class="input-text" maxlength="128" autocomplete="off">

接下来我们使用find_element_by_id() 方法,id值为search来定位搜索框,同时检查maxlength的属性值。

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定位是另外一个常用的查找元素的方式。find_element_by_name() 和 find_elements_by_name()方法可以通过匹配name值来定位单个或一组元素。同样,name值匹配成功可返回定位的元素;反之,则抛出NoSuchElementException的异常。

回到之前的例子,我们可以用匹配name属性值的方式来替换ID值的匹配,同样可以定位到搜索框。

# get the search textbox
self.search_field = self.driver.find_element_by_name("q")

此外,如果使用find_elements_by_name() 方法,那么将返回匹配name值的所有元素。

除了使用ID和name属性,我们还可通过class属性来定位元素。class用来关联CSS中定义的属性。find_element_by_class_name()和find_elements_by_class_name()方法可以通过匹配class属性来定位单个或一组元素。同样,class值匹配成功可返回定位的元素;反之,则抛出NoSuchElementException的异常。

 

通过对元素ID、name和class属性来查找元素是最为普遍和快捷的方法。此外,Selenium WebDriver还提供了其他一些方法用于定位元素,在接下来的段落中会有详细介绍。

同样的场景(见下图),我们可以尝试用find_element_by_class_name() 的方法来定位元素。

搜索按钮(放大镜图标)在HTML中是用<button>标签(元素)以及对应的class属性与属性值定义的,具体如下。

<button type="submit" title="Search"
 class="button"><span><span>Search</span></span></button>

下面我们用class属性值来定位搜索按钮,代码如下。

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() 方法,那么将返回匹配class属性值的所有元素。

find_element_by_tag_name()和find_elements_by_tag_name() 方法是通过对HTML页面中tag name匹配的方式来定位元素的。这些方法跟JavaScript中的DOM方法getElementsBy TagName()类似。同样,通过成功匹配tag name可以返回定位的元素;反之,则抛出NoSuchElementException的异常。

这个方法在某些特定的场景下格外有用,例如,我们可以通过<tr> 的tag name一次定位页面的table中所有的行数据(元素)。

如下图所示的几张banner图,通过查看HTML代码,我们可以看出包含有<img>或者<ul>的标签。

这几张banner图采用无序列表标签<ul>内嵌图像标签<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 & amp; 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-column-
       promo-03.png" alt="Travel Gear for Every Occasion">
    </a>
  </li>
</ul>

我们使用find_elements_by_tag_name()方法来定位所有的banner图片。首先我们用find_element_by_class_name()方法定位这一组banner图,然后用find_elements_by_tag_name()方法去匹配<img>的tag name,最后把结果返回给banners对象。

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(2, len(banners))

XPath是一种在XML文档中搜索和定位元素的查询语言。几乎所有的浏览器都支持XPath。同样,Selenium也可以通过XPath的方式在Web页面上定位元素。

当我们发现通过ID、name或class属性值都无法定位元素时,不妨尝试用XPath的方式。我们可以灵活地运用绝对或相对路径定位,也可以通过除ID、name以外的其他属性来定位,甚至还可以通过属性值的一部分(如starts-with()、contains()和ends-with())来帮助我们定位。

 

了解更多关于XPath的知识,可访问相关网站了解。

想要了解更多关于XPath定位的知识,可以参考《Selenium Testing Tools Cookbook》,Packt Publishing。

接下来,我们可以使用find_element_by_xpath()和find_elements_by_xpath() 方法来定位元素了。例如,我们通过之前的广告banner图,单击banner图片进入对应的页面。

上图是名为“Shop Private Sales”的banner图,在<img> 的tag下,其中代码并不包含ID、name或class属性等信息,且这个页面还包含很多其他的<img>,所以我们不能通过传统的方法如findby tag_name()简单地定位了。

<ul class="promos">
  ...
  <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>
  ...
</ul>

我们尝试使用find_element_by_xpath()方法,用<img>标签下的 alt 属性值来定位我们要找的元素。

代码如下。

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(层叠样式表)是一种用于页面设计(HTML)与表现的文件样式,是一种计算机语言,能灵活地为页面提供各种样式风格。CSS使用选择器为页面元素绑定属性(如ID、class、type、attribute、value等)。

类似XPath,Selenium也可以利用CSS选择器的特性,用于帮助我们来定位元素。如果想进一步了解关于CSS选择器的一些知识,请访问相关网站了解。

下面介绍find_element_by_css_selector()和find_elements_by_css_selector()两种方法。

回到首页的例子,可以看到购物车按钮,单击这个按钮,将进入购物车页面。如果此时没有添加任何商品,那么系统会提示“你还没有添加商品到购物车”,如下图所示。

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>

我们设计测试程序来校验这个提示信息。首先我们将使用CSS选择器来定位购物车按钮,然后单击它,紧接着定位即将弹出的信息。

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()

从上面的测试脚本可以看出,我们使用了元素tag和class name来缩小获取购物车按钮的范围。

shopping_cart_icon = self.driver.\ 
    find_element_by_css_selector("div.header-minicart span.icon")

首先定位到tag 名为<div>的元素,然后接着“.header-minicart”的类名,其下面的标签<span>下又有“.icon”的类名。

想要了解更多关于CSS选择器的知识,请参考《Selenium Testing Tools Cookbook》,Packt Publishing。

find_element_by_link_text() 和 find_elements_by_link_text()方法是通过文本链接来定位元素。如下示例。

(1)定位首页上的Account链接,如下图所示,我们可以使用find_element_by_link_text()方法。

(2)查看对应的HTML代码,具体如下。

<a href="#header-account" class="skip-link skip-account">
 <span class="icon"></span>
 <span class="label">Account</span> 
</a>

(3)编写测试脚本,先通过文本定位Account链接,然后单击查看是否能显示。

def test_my_account_link_is_displayed(self): 
  # get the Account link 
  account_link = 
   self.driver.find_element_by_link_text("ACCOUNT") 

  # check My Account link is displayed/visible in 
  # the Home page footer 
  self.assertTrue(account_link.is_displayed())

此外,如果使用find_elements_by_link_text()方法,那么将返回匹配文本的所有元素。

find_element_by_partial_link_text()和find_elements_by_partial_link_text()两个方法是通过文本链接的一部分文本来定位元素的方法。如下示例。

(1)同样是首页,有两个链接可以查看个人账户(Account)页面,一个是页面标头(header)部分的Account文字链接,另外一个是页脚(footer)部分的My Account文字链接。

(2)我们使用find_elements_by_partial_link_text()方法,通过部分文本信息“Account”来定位,验证页面中的两个文本链接是否都能定位到(断言)。代码如下。

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))

通过前面的介绍,我们尝试了很多种关于find_element_by的方法。接下来我们把这种类型的定位方法集成到同一个测试脚本中来。

(1)创建一个名为homepagetest.py的Python脚本,整合之前我们创建的那些测试代码。

import unittest 
from selenium import webdriver 

class HomePageTest(unittest.TestCase): 
  @classmethod 
  def setUpClass(cls): 
    # create a new Firefox session 
    cls.driver = webdriver.Firefox() 
    cls.driver.implicitly_wait(30) 
    cls.driver.maximize_window() 

    #navigate to the application home page 
    cls.driver.get('http://demo.magentocommerce.com/') 

  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")) 

  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()) 

  def test_my_account_link_is_displayed(self): 
    # get the Account link
    account_link = 
     self.driver.find_element_by_link_text("ACCOUNT") 

    # check My Account link is displayed/visible in 
    # the Home page footer 
    self.assertTrue(account_link.is_displayed()) 

  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)) 

  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 3 banners displayed on the page 
    self.assertEqual(2, len(banners)) 

  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) 

  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() 

  @classmethod 
  def tearDownClass(cls): 
    # close the browser window 
    cls.driver.quit() 

if __name__ == '__main__': 
  unittest.main(verbosity=2)

(2)保存py文件,可以在命令行中直接执行。

python homepagetest.py

(3)执行测试过程中,unittest会打印7组测试的执行结果(OK),如下图所示。

在本章,我们一起学习了许多重要的Selenium定位元素的方法。使用find_element_by方法,通过ID、name、class name、tag name、XPath、CSS选择器以及文本链接(或部分)去定位元素。

在后续设计测试时,可以更灵活地去运用这些定位的策略。这些知识为接下来的章节,如何调用Selenium API奠定了基础。

下一章,将会学习如何使用Selenium WebDriver的功能去与定位到的元素交互,以及模拟用户的操作(例如,在文本框输入、单击按钮、选择下拉菜单、调用JavaScript等操作)。


相关图书

现代软件测试技术之美
现代软件测试技术之美
渗透测试技术
渗透测试技术
JUnit实战(第3版)
JUnit实战(第3版)
深入理解软件性能——一种动态视角
深入理解软件性能——一种动态视角
云原生测试实战
云原生测试实战
Android自动化测试实战:Python+Appium +unittest
Android自动化测试实战:Python+Appium +unittest

相关文章

相关课程