Python-Selenium-测试教程-全-
Python Selenium 测试教程(全)
一、Selenium 简介
在 Selenium 出现之前,测试 web 应用的功能是手工完成的,这需要花费很多时间。测试往往依赖于不同的场景。每个场景都被认为是一个测试用例,用来在实现之前制定 web 应用的行为。这些测试用例被部署在各种浏览器上,以确认源代码中的任何问题。
它需要一个专门的测试团队来检查所有的测试用例。准确性和时间是 web 开发中的主要约束,这导致了自动化测试用例可以在不同的 web 应用中使用,而无需更改源代码。Selenium 是为了自动化测试用例而开发的。
这本书的第一章提供了 Selenium 及其核心架构设计的完整概述。子主题解释了 Selenium 的使用,并将其与该领域中的其他测试工具进行了比较。在本章的后面,将解释 Python 与 Selenium 的集成。让我们从 Selenium 工具的简要历史和描述以及使用它的原因开始。
Selenium 是什么?
Selenium 于 2004 年出现在 ThoughtWorks,用于测试 Jason Huggins 开发的名为 Time and Expenses 的 web 应用。开发该工具是为了在各种浏览器中测试应用的前端行为。这个工具很受欢迎并且是开源的。自动化测试需求的增长导致了几年来 Selenium 的几个版本的开发,这将在下面讨论。
Selenium 工具和版本
ThoughtWorks 发布了 Selenium 的四个主要版本来测试 web 应用。图 1-1 显示了每个版本及其发布年份。
图 1-1
Selenium 套件
组织可以使用这些 Selenium 工具中的任何一个(或多个);选择取决于测试环境的需求。ThoughtWorks 开发的第一个工具是 2004 年的 Selenium Core。它允许测试人员编写他们自己的代码/脚本来自动化前端交互,如键盘或鼠标活动。这些活动类似于用户与应用的交互。
在 web 应用安全性中,有一个策略授予测试脚本访问来自相同来源的网页中的数据的权限;这种策略被称为相同主机策略。同主机策略只允许一个测试用例访问同一个域中的页面。比如一个测试脚本可以访问 www.apress.com
内的多个页面,比如 www.apress.com/in/python
和 www.apress.com/in/about
,因为同宿策略;但是,该策略不允许访问来自不同站点的页面,如 https://google.com
或 https://wikipedia.org
。
由于相同主机策略,当使用外部脚本时,对代码元素的访问被拒绝或阻止。为了避免这种复杂性,Huggins 和 Paul Hammant 开发了一个服务器组件,使您能够用测试脚本测试 web 应用,让浏览器认为两者来自同一来源。这种核心 Selenium 最终被称为驱动 Selenium 或 Selenium b。
Selenium 遥控(遥控)
Selenium RC (remote control)是由 Dan Fabulich 和 Nelson Sproul 在 2005 年部署的,它支持使用 HTTP 代理的独立服务器。这解决了 Selenium Core 在相同主机策略下面临的问题。Selenium RC 分为两部分:Selenium 远程服务器和远程客户端。服务器和客户端接收和发送 HTTP 请求所花费的时间导致测试用例的执行速度变慢;因此,Selenium RC 成为最少使用的工具。
Selenium IDE
2006 年,Shinya Kasatani 为测试人员开发了一个完全集成的开发环境(IDE)。它是以 Mozilla Firefox 和 Google Chrome 网络浏览器插件的形式出现的。Selenium IDE 在真实环境中进行了功能测试。这个 IDE 的特性包括记录/重放和调试/编辑测试,这就是 Selenium Recorder。记录脚本存储在一个名为 Selenium 的测试脚本中。测试脚本是用 Java、Ruby、JavaScript 和 PHP 等语言编写的。IDE 还为针对 web 应用执行的测试用例提供了数据检索选项。Selenium IDE 目前由 Kantu 和 Katalon 积极维护。
Selenium 栅
很难在市场上出现的新技术设备上测试 web 应用。为了解决这个问题,2008 年,ThoughtWorks 的 Philippe Hanrigou 开发了一种网格架构,允许您通过浏览器在任意数量的远程设备上测试应用,这就是后来的 Selenium Grid。它减少了在任意数量的远程设备上测试脚本的时间,因为它是并行完成的。test 命令通过浏览器测试远程设备。在远程设备上执行测试脚本需要两个组件:集线器/服务器和节点/远程设备。
集线器/服务器从允许访问的 web 驱动程序客户端获取请求,并将其路由到远程驱动程序。这些驱动程序在远程设备上注册。节点/远程设备具有本地操作系统和浏览器。web 驱动程序是执行测试的浏览器的一部分。在定义脚本时,您需要命名一个远程设备、平台、浏览器等等,以定位一个特定的节点,然后为该节点执行测试脚本。
Selenium WebDriver
Selenium WebDriver 是一个广泛使用的工具。Selenium RC 的进步导致了 Selenium WebDriver 的开发。WebDriver 中的命令通过客户端 API 接受,并被发送到不同的浏览器,如 Mozilla Firefox、Apple Safari 等。几乎所有的浏览器都支持 Selenium WebDriver。每个浏览器都有一个与之相关的特定驱动程序,如表 1-1 所列。
表 1-1
Web 浏览器及其各自的 Selenium 驱动程序
|网络浏览器
|
驱动程序名称
|
| --- | --- |
| Mozilla Firefox | Firefox(即壁虎) |
| 谷歌浏览器 | 铬 |
| 苹果浏览器 | 旅行队 |
| 歌剧 | 歌剧 |
| 浏览器 | 微软公司出品的 web 浏览器 |
| 微软边缘 | 边缘 |
维护表中列出的每个驱动程序,以支持其各自浏览器的自动化。另一个浏览器驱动程序 HTMLUnitDriver 使用一个无头浏览器(HtmlUnit)来模拟浏览器。
Selenium WebDriver 允许您直接启动 web 浏览器,并通过执行命令来管理它。为了避免安全冲突和问题,WebDriver 使用本机操作系统功能,而不是基于浏览器的 JavaScript 命令。WebDriver 的 Selenium WebDriver 版本专注于接口。之后的版本是 Selenium 2.0 和 Selenium 3.0。
Selenium 2.0
2007 年,ThoughtWorks 的 Simon Stewart 开发了 Selenium 2.0,它可以在几乎所有的浏览器上实现自动化。这个版本调用更少,允许测试人员/开发人员创建他们自己的领域特定语言(DSL)。用 Ruby 实现的 Watir web 驱动程序是 DSL 最好的例子之一。
Selenium 3.0
开发人员西蒙·斯图尔特(Simon Stewart)和大卫·伯恩斯(David Burns)制定了一个草案来标准化 Selenium,该草案被完全接受,并在 2019 年成为 W3C 标准协议,当时它被称为 Selenium 3.0。
这就完成了 Selenium 及其多年演变的概述;现在,在深入测试用例之前,让我们考虑一下 Selenium 架构,这将在本书接下来的章节中介绍。
Selenium WebDriver 架构
现在您已经了解了 Selenium 的各种工具和版本,让我们来看看一个帮助 web 应用自动化测试脚本的工具。为了自动化一个测试脚本,在工具和浏览器之间有一个只有它的架构才能理解的交互。
Selenium WebDriver 是 Selenium 套件中的一个工具,可以为任何 web 应用自动化测试用例。web 驱动工具和应用之间的交互经历了不同的阶段。这些阶段形成了一个架构,如图 1-2 所示。Selenium WebDriver 的架构由三个主要组件组成:Selenium 客户端库、浏览器驱动程序和 web 浏览器。组件之间的通信是通过 JSON 协议完成的。
图 1-2
Selenium WebDriver 架构
客户端库
客户机库是 Selenium 支持的语言包。Selenium 支持的核心语言有 Python、Java、JavaScript、Ruby、C# ( https://selenium.dev/downloads/
)。像 Perl、PHP、GO、DART、R、Haskell 等语言都是由第三方维护开发的( https://selenium.dev/thirdparty/
)。Selenium 不正式支持这些第三方语言绑定。
JSON 有线协议
JSON 是 JavaScript Object Notation 的首字母缩写,它是一种轻量级协议,在客户机和服务器之间交换数据或信息,反之亦然。JSON 是一种易于理解的文本格式,这使得 ThoughtWorks 开发人员能够使用 JSON wire 协议在客户端库和 web 浏览器驱动程序之间进行通信。服务器不关心客户端使用的语言;它只能从协议中读取以 JSON 格式接收的数据。JSON wire 协议将任何数据或信息在发送到服务器之前都转换成 JSON 格式。这是一个 REST API。
Note
REST(表述性状态转移)定义了一套开发 API(应用编程接口)的准则。规则之一是当链接到一个 URL 时从源获得服务器响应。
Web 驱动程序
每个浏览器都有一个相关联的网络驱动程序(更多信息请参考表 1-1 )。这些 web 驱动程序负责执行从客户端库接收的命令。这些命令的执行是在 web 浏览器中完成的,它通过 HTTP 进行通信。
网络浏览器
执行从 web 驱动程序的 HTTP 响应中收到的命令。像客户端库一样,可以使用核心和第三方浏览器。Selenium 支持的浏览器有 Firefox、Internet Explorer、Safari、Opera、Chrome 和 Edge。这些浏览器可以在任何操作系统上运行,比如 Windows、macOS 或 Linux。有为这些 web 浏览器开发的第三方 web 驱动程序,但不推荐使用。
为什么是 Selenium?
研究了 Selenium WebDriver 架构之后,让我们进一步加深您对 Selenium 的理解。
由于市场上测试工具的可用性,出现了一个问题:为什么使用 Selenium 进行测试?这个问题有几个答案,但是使用 Selenium 的主要原因是它是开源的(即可以免费使用)。接下来讨论使用 Selenium 作为测试工具的好处。
开放源码
Selenium 是开源的,可以免费使用。有一个庞大的开发人员/测试人员社区在持续维护和支持它。您可以为任何测试环境修改、集成或扩展 Selenium,因为代码是开源的。
平台
Selenium WebDriver 是跨平台的,这意味着它可以灵活地在任何操作系统中自动化测试用例,比如 Windows、macOS、Unix 和 Linux。这些在一个操作系统中编写的测试用例可以在任何其他操作系统中使用。
语言支持
Selenium 拥有大型社区的另一个原因是它支持多种编程语言和脚本,如 Python、Java、Ruby、Perl、PHP、JavaScript、Groovy、GO、DART 等等。Selenium WebDriver 语言绑定/客户端库支持这一点。
浏览器
与平台灵活性一样,Selenium WebDriver 支持几乎所有的浏览器。支持 Mozilla Firefox、Google Chrome、Safari、Opera、Internet Explorer、Edge 它们是全球使用最广泛的。
再用
一旦编写完成,测试脚本可以根据需要跨任何浏览器或操作系统使用。对多次使用一个测试脚本没有限制。
易于实施
Selenium WebDriver 的实现依赖于开发人员/测试人员或组织所使用的环境和脚本。这种多样性源于大量潜在的操作系统和浏览器组合。您可以开发定制的 web 驱动程序或框架,以便在特定的测试环境中实现。
灵活的
在测试脚本中进行重构或重组,可以让您减少代码重复和其他复杂性。Selenium 在测试脚本中为开发人员/测试人员提供了这种灵活性。
硬件资源
与其他测试工具(如 UFT、CompleteTest、Katalon Studio 等)不同,Selenium 需要的硬件资源更少。
模拟
Selenium 的模拟创建了鼠标和键盘的实时行为。这有助于使用鼠标测试高级事件,如拖动、放下、单击、按住、滚动等,以及在键盘上进行类似的按键事件。
到目前为止讨论的各种原因应该满足使用 Selenium 作为测试工具的理由,但是与其他可用的工具进行比较可以确保 Selenium 在自动化测试方面是最好的。这将在下面讨论。
其他测试工具
既然您已经知道了 Selenium 提供的好处,现在让我们将 Selenium 与测试领域中其他可用的测试工具进行比较。这个比较显示了在 Python 中使用 Selenium 的确切原因。对测试工具的各种特性进行了比较。还有其他四种主要的测试工具可用。表 1-2 展示了这些测试工具。
表 1-2
将 Selenium 与其他测试工具进行比较
| |Selenium
|
加泰罗尼亚工作室
|
UFT(统一功能测试)
|
测试完成
|
沃特沃特 Walter
|
| --- | --- | --- | --- | --- | --- |
| 发布年份 | Two thousand and four | Two thousand and fifteen | One thousand nine hundred and ninety-eight | One thousand nine hundred and ninety-nine | Two thousand and eight |
| 测试平台 | 十字架 | 十字架 | Windows 操作系统 | Windows 操作系统 | 十字架 |
| 测试应用 | 开发 | 网络/移动应用、API/网络服务 | Windows/web/移动应用,API/web 服务 | Windows/web/移动应用,API/web 服务 | 网络/移动应用 |
| 语言支持 | Python,Java,C#,Perl,JavaScript,Ruby,PHP | Java/Groovy | 脚本语言 | Python、JavaScript、VBScript、Jscript、Delphi、C++、C# | 红宝石 |
| 安装过程 | 易于过渡(取决于 Selenium 工具) | 容易的 | 容易的 | 容易的 | 先进的 |
| 编程技巧 | 中级到高级(用于编写所需的测试用例) | 先进的 | 先进的 | 先进的 | 先进的 |
| 成本 | 自由的 | 自由的 | 许可维护费 | 许可维护费 | 自由的 |
| 许可证类型 | 开源(Apache2.0) | 免费软件 | 所有人 | 所有人 | 开源(麻省理工学院许可) |
| 产品支持 | 开源社区 | 社区/业务支持 | 敬业的工作人员/社区 | 敬业的工作人员/社区 | 开源社区 |
现在您可以看到 Selenium 是测试 web 应用的最合适的自动化工具,让我们看看为什么 Python 是与 Selenium 集成的最佳语言。
将 Python 与 Selenium 集成
现在,Selenium WebDriver
已经讨论过了,您可能想知道使用哪种语言来自动化测试脚本或用例。Selenium WebDriver 支持多种语言。下面列出了 Python 是最适合测试的语言的原因。
-
Python 是在英语范围内开发的,所以代码语法很容易阅读。
-
Python 脚本不是机器级别的代码,这使得编码很容易。
-
Python 提供跨平台支持,这导致了一个庞大的追随者社区。
-
在 Selenium WebDriver 上安装 Python 比任何其他语言都容易。
-
Python 支持 web 和移动应用的开发。Python 开发人员可以很容易地迁移到 Selenium WebDriver 来测试他们的应用,因为 Selenium 在 Python 中受支持。
-
Selenium 提供了直接连接到浏览器的 Python API。由于 Python 不太冗长,Selenium 命令在连接到任何受支持的浏览器时都很容易编写和执行。
-
Python 编程语言是一个脚本;因此,不需要编译器将代码从一种形式转换成另一种形式。
-
Python 有巨大的库支持,因为它背后有大量的社区,他们定期维护和更新它。Selenium WebDriver 可以根据组织或个人的需要通过自动化来扩展,以构建更高级的测试用例。
-
Python 库也支持不同的语言绑定。这有助于自动化用其他语言开发的应用的测试用例。
清单 1-1 到 1-5 为 Selenium WebDriver 支持的语言提供了一个简单的程序。该程序打开浏览器,访问指定的 URL,并在其中搜索查询。该程序首先导入必要的 Selenium WebDriver 库。WebDriver 然后打开 Mozilla Firefox 浏览器,指定 www。阿普瑞斯。com 作为访问的网址。接下来,它在 press 站点中定位搜索栏元素。找到元素后,这本书的书名Python Testing with Selenium,作为查询输入搜索栏并提交。提交的查询提供了一个新的网页,其中包含与该查询相关联的书籍。
清单 1-1 到 1-5 展示了与 Java、C#、Ruby 和 PHP 等其他编程语言相比,Python 使用 Selenium web driver 实现测试用例是多么容易。
<?php
require_once('vendor/autoload.php');
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;
$web_driver = RemoteWebDriver::create(
"https://api_key:api_secret@hub.testingbot.com/wd/hub",
array("platform"=>"WINDOWS", "browserName"=>"chrome", "version" => "latest", "name" => "First Test"), 120000
);
$web_driver->get("http://apress.com");
$element = $web_driver->findElement(WebDriverBy::name("query"));
if($element) {
$element->sendKeys("Python with Selenium");
$element->submit();
}
print$web_driver->getTitle();
$web_driver->quit();
?>
Listing 1-5PHP Code
//Library Import
require "selenium-webdriver"
// Open Firefox
browser= Selenium::WebDriver.for:firefox
// Visit Apress Site
browser.navigate.to "http://www.apress.com"
// Finding Element of search bar
search=browser.find_element(:name, 'query')
// Search Book name
search.send_keys"Python Testing with Selenium"
// Submit book name
search.submit
//Closing browser
browser.close
Listing 1-4Ruby Code
//Importing Libraries in C#
using System;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
class Apress
{
staticvoid Main()
{
// Opening Browser
WebDriver browser = newFirefoxDriver();
// Visit Apress Site
browser.Navigate().GoToUrl("http://www.apress.com");
// Finding Element of search bar by name
WebElement search = driver.FindElement(By.Name("query"));
// Search Book name
search.SendKeys("Python Testing with Selenium");
// Submit book name
search.Submit();
// Submit book name
browser.Close();
}
}
Listing 1-3C# Code
//Importing Libraries in JAVA
importorg.openqa.selenium.By;
importorg.openqa.selenium.WebDriver;
importorg.openqa.selenium.WebElement;
importorg.openqa.selenium.firefox.FirefoxDriver;
public class Search {
public static void main(String[] args) {
//Opening Firefox Browser
WebDriver browser = new FirefoxDriver();
//Opening Apress Website
browser.get("http://www.apress.com");
//Finding Element of search bar
WebElement search =driver.findElement(By.name("query"));
//Searching book name as query
search.sendKeys("Python Testing with Selenium");
//Submitting the query
search.submit();
//Closing browser
browser.close();
}
}
Listing 1-2Java Code
#Importing selenium libraries in python
from selenium import webdriver
#Opening web Firefox browser using webdriver
driver=webdriver.Firefox()
#Adding URL to open in browser
driver.get("http://www.apress.com")
#Finding Element of search bar
search=driver.find_element_by_name("query")
#Searching book name as string/query in search bar
search.send_keys("Python Testing with Selenium")
#Submit string to search bar
search.submit()
# Close Firefox browser
driver.quit()
Listing 1-1Python Code
摘要
本章概述了 Selenium WebDriver,包括对其各种版本的介绍。重点是 Selenium 的架构设计,它提供了自动化测试用例所必需的完整交互过程。讨论了 Selenium 的重要性,包括它的多种好处以及它与其他主要测试工具的区别。在本章的最后,使用 Python 和其他语言在简单的测试案例场景中展示了 Python 与 Selenium 集成的重要性。我们进一步研究如何在不同的环境中进行集成。Python 的设置和配置将在下一章阐述。
二、入门指南
在前一章中,讨论了 Selenium 及其架构设计的完整概述,包括将 Python 与 Selenium 集成的意义。现在让我们深入了解集成。
本章涵盖了使用 Selenium 和 Python 编写自动化测试用例的基本构件。它解释了所需工具的配置和安装,包括 Selenium 库。它还介绍了与各种浏览器相关的 Selenium 驱动程序的配置。
在写测试用例之前,你需要知道初始化测试用例的浏览器命令,这在本章的例子中有所说明。
Note
Selenium 中的 Python 脚本被描述为一个测试用例。
本章的前半部分致力于 Python 编程语言、Selenium 包和可用驱动程序的安装。本章的后半部分介绍了使用安装的 web 驱动程序运行测试用例所必需的基本浏览器命令。让我们从基本的 Python 安装开始。
安装 Python
首先,你需要安装 Python。如果您不熟悉 Python,请按照以下步骤在 Windows 中安装它。
-
打开浏览器,进入
https://python.org/downloads/windows/
。 -
下载标题为 Python Releases for Windows 下的任何版本。(选择高于 3.6.0 的 Python 版本;撰写本文时的最新发布版本是 3.8.5。)
-
选择 Windows 版本(64 位的 Windows x86-64 可执行安装程序或 32 位的 Windows x86 可执行安装程序)。
-
运行 Python 安装程序,并向其中添加 Python 路径。
注意 Python 预装在 Mac 和 Linux 上。
现在您可以为 Python 安装 Selenium 库了,这将在下面解释。
安装 Selenium
一旦 Python 安装在您的系统上,您就可以利用 pip 下载 Selenium 包。使用 pip 安装 Selenium 的命令是
pip install selenium
通过用另一个包名替换selenium
,同样的语法可以用于其他的包安装,这将在本书的另一章中讨论。本书使用的 Selenium 版本是 3.141.0。如果已经安装了 Selenium 库的较低版本,或者需要升级当前版本,请使用下面的命令。
pip install --upgrade selenium
接下来解释下一个过程,Selenium 支持的驱动程序安装。
安装驱动程序
需要驱动程序才能与指定的浏览器交互。每个浏览器都有一个特定的 Selenium WebDriver 与之关联,因此您需要安装所提供的任何一个驱动程序;例如,geckodriver 是一个 Selenium WebDriver,它只能在 Mozilla Firefox 上运行。表 2-1 列出了每个驱动程序及其相关的安装源。
表 2-1
Web 驱动程序和安装源
|Web 驱动程序
|
来源
|
| --- | --- |
| Mozilla Firefox | https://github.com/mozilla/geckodriver/releases
|
| 谷歌浏览器 | https://sites.google.com/a/chromium.org/chromedriver/downloads
|
| 微软边缘 | https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
|
| 苹果浏览器 | https://webkit.org/blog/6900/webdriver-support-in-safari-10/
|
安装完您选择的驱动程序后,您需要学习与浏览器相关的基本命令。这些浏览器命令是运行书中解释的任何测试用例所必需的。接下来让我们看看各种浏览器命令。
浏览器命令
现在让我们看看如何在不同的浏览器中运行一个测试用例。这是运行测试用例的第一步。稍后,将讨论每个浏览器命令。
要在 Selenium 中初始化测试用例,您需要知道基本的浏览器命令。打开指定的 web 浏览器对于任何测试用例的发生都是强制性的。下面讨论可用的命令。
打开 Web 浏览器
Selenium 支持多种 web 浏览器,每种浏览器都有自己的驱动程序。应该使用相关驱动程序的可执行路径来打开任何 web 浏览器。打开驱动程序的语法是
driver = webdriver.Browser_name(executable_path="driver_path")
Mozilla Firefox
在打开 Firefox 之前,需要导入必要的 Selenium 库。应该创建 WebDriver 实例来打开此浏览器。
#Import Selenium Library
from selenium import webdriver
#Open Mozilla Firefox
driver = webdriver.Firefox(executable_path=r'C:\Driver\path\ \geckodriver.exe')
谷歌 Chrome
在 Chrome 中执行任何测试用例之前,需要安装 Chrome 驱动程序。您可以使用以下命令在此浏览器中进行测试。
from selenium import webdriver
#Open Google Chrome
driver = webdriver.Chrome(executable_path=r'D:\chromedriver.exe')
微软边缘
要在微软 Edge 浏览器中测试一个案例,需要安装 Edge 驱动,然后使用 Selenium WebDriver 执行。
from selenium import webdriver
#Open Microsoft Edge
driver = webdriver.Edge(executable_path=r'D:\msedgedriver.exe')
微软公司出品的 web 浏览器
在该浏览器中测试案例需要 Internet Explorer 可执行文件的路径。
#Import Selenium Library
from selenium import webdriver
#Open Internet Explorer
driver = webdriver.Ie(executable_path=r'D:\IEdriverserver.exe')
Note
Mozilla Firefox 是本书中最常用的网络驱动。
关闭浏览器
close()
函数使用 Selenium 驱动程序关闭当前打开的窗口。它不影响打开的其他窗口。执行过程保持活动状态。
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('https://apress.com')
print("Browser Window opened")
#Close function
driver.close()
print("Browser Window closed")
退出浏览器
quit()
功能关闭所有打开的窗口。它还终止驱动程序的执行过程。
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('https://google.com')
print("Browser opened")
#Quit function
driver.quit()
print("Terminates process")
打开网页
测试在网页打开时进行,web 元素被包装在其中。网页可以在线或离线打开(即,有或没有任何互联网连接)。为了打开一个 web 页面,Selenium 使用了get()
方法,该方法初始化将在指定浏览器中加载的页面。有两种打开网页的方法,下面将讨论这两种方法。
在线打开页面
HTTP 或 HTTPS 协议用于打开在线 web 应用或页面。get()
方法完成网页的加载,然后将控制权转移到下一行代码。
from selenium import webdriver
driver = webdriver.Firefox()
#Open web page online
driver.get('https://apress.com')
print("Page opened Online")
脱机打开网页
离线打开页面用于在本地测试网页或 web 应用。要执行测试,您需要将文件本地存储在计算机上。这适用于不需要互联网连接的页面。您需要提供文件位置而不是 URL,以便在浏览器中打开它。
from selenium import webdriver
driver = webdriver.Firefox()
#Open web page offline
driver.get('file:///C:/File/Path/file_name.html')
print("Page opened Offline ")
表 2-2 描述了get()
方法打开网页所支持的协议。
表 2-2
get()方法支持的协议
|协议
|
描述
|
| --- | --- |
| 文件 | 用于存储在本地计算机上的网页 |
| 超文本传送协议 | 测试服务器上承载的网页 |
| 安全超文本传输协议 | 在服务器上进行测试时,有两种不同的协议与域相关联,即 HTTP 或 HTTPS。 |
当协议不匹配时,Selenium 抛出一个异常。
设置浏览器大小
大多数 web 应用或网页都是使用响应式框架开发的。响应网页根据浏览器大小进行调整。为了测试不同浏览器大小的页面,Selenium 提供了下面讨论的命令。
达到最大值
Selenium 中的maximize
功能最大化当前网页浏览器。测试人员用它来测试网页的响应性。当它没有以最大化状态打开时,由浏览器使用。
from selenium import webdriver
driver = webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
#Open apress webpage
driver.get('https://apress.com')
#Maximise Window
driver.maximize_window()
print("Browser is maximised")
当浏览器已经处于最大化状态时,该功能对浏览器没有任何影响。
全屏
fullscreen
功能将浏览器设置为全屏模式。标题、URL、地址栏、选项卡等在全屏显示的网页上是不可见的。
from selenium import webdriver
driver = webdriver.Firefox()
#Open apress webpage
driver.get('https://apress.com')
#FullScreen
driver.fullscreen_window()
print("Browser is Fullscreen")
设置尺寸
这个函数通过设置高度和宽度来调整浏览器窗口的大小。调整浏览器大小以测试 web 应用/页面的响应性。
from selenium import webdriver
driver = webdriver.Firefox()
#Open apress webpage
driver.get('https://apress.com')
#Set Window Size
driver.set_window_size(500,400)
print("Sets Browser Size")
设置浏览器位置
Python Selenium 中的set
方法沿着 x 和 y 轴设置浏览器位置。x 和 y 的位置从屏幕右上角的(0,0)开始。
from selenium import webdriver
driver = webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
#Open apress webpage
driver.get('https://apress.com')
#Set Window Position
driver.set_window_position(x=500,y=400)
print("Sets Browser Position")
使用坐标设置大小
此方法用位置和尺寸设置浏览器。位置与 x 和 y 坐标有关,而尺寸与高度和宽度有关。
from selenium import webdriver
driver = webdriver.Firefox()
#Open apress webpage
driver.get('https://apress.com')
#Set Window Size with co-ordinates
driver.set_window_rect(x=30, y=30, width=450, height=500)
print("Sets Browser Size with co-ordinates")
获取浏览器位置
在一些测试用例中,浏览器位置是执行基于它的动作所必需的。get
方法返回浏览器窗口相对于 Python 字典中 x 和 y 位置的位置。
from selenium import webdriver
driver = webdriver.Firefox()
#Open apress webpage
driver.get('https://apress.com')
#Get Window Position
window_pos= driver.get_window_position()
print(window_pos)
获取窗口大小
使用此函数时,浏览器窗口的高度和宽度将在 Python 字典中返回。
from selenium import webdriver
driver = webdriver.Firefox()
#Open apress webpage
driver.get('https://apress.com')
#Get Window Size
print(driver.get_window_size())
导航命令
导航命令与浏览器特征相关,浏览器特征使得测试者能够通过使用后退和前进命令或刷新命令来导航浏览历史。Python Selenium 支持这些命令。
背部
back()
功能用于在同一个浏览器标签中导航到以前访问过的页面。
from selenium import webdriver
driver = webdriver.Firefox()
#Open apress webpage
driver.get('https://apress.com')
#Open Google page
driver.get('https://google.com')
#Go back to previous 'apress' page
driver.back()
print("Moved to first page")
向前
此功能有助于点击网络浏览器的forward
按钮,最终进入下一页(如果可用)。
from selenium import webdriver
driver = webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
#Open apress webpage
driver.get('https://apress.com')
#Open Google page
driver.get('https://google.com')
#Go back to previous 'apress' page
driver.back()
print("Moved to first page")
#Go to current page
driver.forward()
print("Moved to second page")
恢复精神
refresh()
功能在网络浏览器中重新加载当前页面。
from selenium import webdriver
driver = webdriver.Firefox()
#Open apress webpage
driver.get('https://apress.com')
print("Page will be Refreshed")
#Page refresh command
driver.refresh()
print("Page is Refreshed")
接下来讨论运行测试用例的传统方式。
运行 Python 测试用例
现在让我们运行 Python 文件(即测试用例)。运行测试用例的过程只需要几个简单的步骤。
下面解释了如何在 Windows 中执行 Python 测试用例文件。
-
单击位于屏幕左下角的 Windows 按钮。
-
输入
cmd
关键字,这是命令提示符的快捷方式。点击它。 -
使用以下命令将路径更改为测试用例所在的文件位置。
-
使用以下命令运行测试用例。
cd dsktop/selenium
python file_name.py
.py
是 Python Selenium 的测试用例扩展。
摘要
在本章中,您学习了安装 Python 及其 Selenium 库的基本过程。本章还解释了在 Selenium 环境中安装和实现一些 web 驱动程序。您了解了每个 web 驱动程序的初始化以及一些相关的浏览器命令。随着您逐步阅读下一章,这些基本的浏览器命令会变得更加具体。在本章的最后,你经历了一个运行测试用例的过程化方法。
下一章解释了使用相同 web 浏览器命令的鼠标和键盘操作。
三、鼠标和键盘操作
前一章介绍了用 Selenium 安装和配置 Python 来自动化测试用例。还回顾了在 WebDriver 中运行测试用例所必需的基本 web 浏览器命令。本章将指导您完成用户使用鼠标和键盘在 web 应用中进行的所有操作。
在 web 应用中,web 元素被绑定到某些需要执行的动作或事件,以执行一个完整的测试用例。当用 Selenium 操作命令测试这些操作或事件时,会发现与用户界面相关的错误。
在 web 应用中,用户/客户端使用各种鼠标和键盘操作。Selenium 提供了 ActionChain,这是一个强大的库函数,用于测试页面上任何 UI 元素的用户行为。在 UI 元素上执行动作功能之前,您需要定位它(参见第四章)。
动作链
ActionChains 在一个测试用例中自动化了低级别的鼠标和键盘交互。交互通过设备(即鼠标或键盘)进行分类,并根据与之相关的类似事件进一步分类。
perform()
是一个重要的功能,使鼠标和键盘的所有动作得以执行。只有在使用perform()
功能时,与鼠标和键盘相关的所有 ActionChains 功能才起作用;如果没有使用,ActionChain 函数将不会在网页上执行任何操作。
当用于 web 元素时,多个操作在队列中对齐。这些动作在调用perform()
函数后执行。在使用perform()
功能之前需要进行操作(稍后将演示鼠标和键盘操作的示例)。现在让我们检查一些与鼠标相关的动作。
老鼠
鼠标可以执行点击、拖动、移动等操作和动作。这些操作是通过 web 应用中的 web 元素执行的。例如,按钮的选择,如默认提交按钮,是通过点击鼠标完成的(参见第六章),或者在执行此操作后显示或定位一个 web 元素。
可以通过单击或多次单击鼠标左键或右键来完成单击。Python 中的 Selenium 提供了测试与鼠标相关的动作的方法,这将在下面描述。
点击
click(web_element)
是通过点击鼠标左键选择网页元素的功能。传递的参数用于一个需要选择或单击的 web 元素。
当没有参数(即 web 元素)被传递时,鼠标左键被点击到它在 web 应用中的当前位置。
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Firefox()
driver.get("http://www.apress.com")
# Go to button
web_element=driver.find_element_by_link_text("Apress Access")
#Clicking on the button to be selected
web_element.click()
点击并按住
click_and_hold(web_element)
是一种方法,首先将鼠标指针移动到特定的 web 元素,然后使用鼠标左键单击相同的元素。单击后,元素不会被释放,因此会保持不动。
在下面的示例中,单击并按住元素的中间。
from selenium import webdriver
driver=webdriver.Firefox()
# Direct to url
driver.get("http://www.apress.com")
# Locate 'Apress Access' web element button
button=driver.find_element_by_link_text("Apress Access")
# Execute click-and-hold action on the element
webdriver.ActionChains(driver).click_and_hold(button).perform()
上下文点击
context_click(web_element)
是一个将鼠标指针移动到特定 web 元素的函数,然后在该元素上启动上下文点击。鼠标右键点击在 ActionChains 中被称为上下文点击。
这里有一个例子。
driver.get("http://www.apress.com")
# Go to button
button=driver.find_element_by_link_text("Apress Access")
# Perform context-click
webdriver.ActionChains(driver).context_click(button).perform()
如果在上下文函数中没有定义 web 元素,那么在当前位置单击鼠标按钮。
双击
double_click(web_element)
是一种方法,鼠标指针指向定位的 web 元素,然后双击鼠标左键(双击)。
这里有一个例子。
driver.get("http://www.apress.com")
# Go to button
button=driver.find_element_by_link_text("Apress Access")
# Double click on button
webdriver.ActionChains(driver).double_click(on_element=button).perform()
当没有指定元素时,它单击当前位置。
移动到一个元素
move_to_element(web_element)
函数将鼠标移动到 web 元素上。它主要集中在下拉菜单上,在那里你可以滚动或点击鼠标。
这里有一个例子。
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
driver= webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
driver.get("http://www.apress.com")
main_menu=driver.find_element_by_link_text("CATEGORIES")
ActionChains(driver)\
.move_to_element(main_menu)\
.perform()
# Wait for sub menu to be displayed
WebDriverWait(driver, 3).until(EC.visibility_of_element_located((By.LINK_TEXT, "Python")))
sub_menu=driver.find_element_by_link_text("Python")
sub_menu.click()
(除了 ActionChains(将在后续章节中讨论)之外,还有其他一些与异常和等待相关的库导入。)程序将鼠标指针移动到主菜单中的 Categories 链接,并等待三秒钟跳转到 Python 子菜单。
移动偏移量
鼠标从当前位置移动到指定的 x 和 y 偏移量。函数中的 x 和 y 偏移值是一个整数,可以是正数也可以是负数。下面是语法。
move_by_offset(xoffset, yoffset)
driver.get("http://www.apress.com")
#Offset positions of x and y
x =268
y =66
#Move element with offset position defined
webdriver.ActionChains(driver).move_by_offset(x,y).perform()
当指定的坐标超出网页窗口时,则鼠标移出窗口。偏移的默认坐标是(0,0)。
下面的语法反映了用指定的坐标移动鼠标。这里,鼠标相对于元素位置移动。早期的方法是将鼠标的移动作为一帧覆盖整个屏幕。
move_to_element_with_offset(to_element, xoffset, yoffset)
偏移值从任何指定 web 元素的左上角开始。该值是一个整数,可以是正数,也可以是负数。负的xoffset
值表示指定 web 元素的左侧。类似地,yoffset
中的负值表示 web 元素向上的一侧。下面是这个函数的一个例子。
driver.get("https://www.apress.com/")
# get element
element = driver.find_element_by_link_text("CATEGORIES")
# create action chain object
action = ActionChains(driver)
# perform the operation
action.move_to_element_with_offset(element, 200, 50).click().perform()
当 web 元素静态放置在网页上时,可以使用偏移位置,但不能用于相对位置。
拖放
drag_and_drop()
拖动源元素到指定或目标位置。源元素是需要被拖到目标位置的 web 元素。
以下是拖放元素的 HTML 代码。
<html>
<head>
<style type="text/css">
#drag,#drop {
float:left;padding:15px;margin:15px;-moz-user-select:none;
}
#drag{ background-color:#A9A9A9; height:50px; width:50px; border-radius:50%; }
#drop{ background-color:#fd8166; height:100px; width:100px; border-radius:50%; }
</style>
<script type="text/javascript">
function dragStart(ev) {
ev.dataTransfer.setData("Text", ev.target.getAttribute('id'));
ev.dataTransfer.effectAllowed='move';
ev.dataTransfer.setDragImage(ev.target,0,0);
return true;
}
function dragEnter(ev) {
event.preventDefault();
return true;
}
function dragOver(ev) {
return false;
}
function dragDrop(ev) {
var src=ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(src));
ev.stopPropagation();
return false;
}
</script>
</head>
<body>
<h1>Drag and Drop</h1>
<center>
<div id="drop" ondragenter="return dragEnter(event)" ondrop="return dragDrop(event)" ondragover="return dragOver(event)">Drop here</div>
<div id="drag" draggable="true" ondragstart="return dragStart(event)">
<p>Drag</p>
</div>
</center>
</body>
</html>
为这两个元素定义了两个圆,其中一个元素可以拖动较小的圆放到较大的圆上。这是一个拖放元素的简单例子。在网页上,拖放功能通常用于将图像滑块或文件移动到上传的特定区域。
下面是 Selenium 代码来拖拽图 3-1 所示的圆。
图 3-1
拖放
from selenium import webdriver
driver=webdriver.Chrome()
# Navigate to page stored as local file
driver.get("drag_and_drop.html")
# Locate 'drag' element as source
element1 =driver.find_element_by_id("drag")
# Locate 'drop' element as target
element2 =driver.find_element_by_id("drop")
# Perform drag and drop action from
webdriver.ActionChains(driver).drag_and_drop(element1,element2).perform()
拖放通过
使用drag_and_drop_by
(source, x_offset, y_offset)
,按住鼠标左键,直到它将 web 元素分别移动到定义的 x 和 y 偏移值,然后松开按钮。web 元素是给定语法中的源元素。
这里有一个例子。
driver.get("drag_and_drop.html")
#Locate circle1 element
circle1 =driver.find_element_by_id("drag")
#Locate circle2 element
circle2 =driver.find_element_by_id("drop")
#Getting offset values
x_off=circle2.location.get("x")
y_off=circle2.location.get("y")
#PerformdragAndDropBy to circle2 element
webdriver.ActionChains(driver).drag_and_drop_by_offset(circle1, x_off, y_off).perform()
Note
由于 Firefox 和 Selenium 之间的兼容性问题,普通 JavaScript 使用的拖放功能可能不起作用。
释放;排放;发布
release()
功能释放被点击的鼠标左键。它对于与拖放相关的 web 元素最为有效。如果没有 web 元素被传递,那么鼠标按钮在网页上的当前位置被释放。
这里有一个例子。
driver.get("drag_and_drop.html")
#Locate circle1 element
circle1 =driver.find_element_by_id("drag")
#Locate circle2 element
circle2 =driver.find_element_by_id("drop")
#Release action after performing necessary actions
ActionChains(driver)
.click_and_hold(circle1)
.move_to_element(circle2)
.perform()
.release()
.perform()
既然我们已经回顾了 Selenium 中 ActionChains 的所有鼠标操作,现在让我们来看看键盘操作。
键盘操作
键盘操作也是与 web 应用交互所必需的。四个主要动作与键盘相关联。接下来将讨论这些操作。
向下按键
key_down(value, web_element)
功能通过按键来工作。它主要与修饰键一起使用,如 Shift、Control、Alt 等。
键起
key_up(value, web_element)
功能释放按下的修改键。它通常在 key down 方法之后使用。
发送密钥
send_keys_to_element( send_keys)
方法将键盘上的按键发送到当前选中的 web 元素。它可用于单键或多键。
大多数时候,键盘动作是一起使用的。下面是从网页中选择和复制文本的键盘操作的简单示例。
#Import necessary libraries
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
driver=webdriver.Chrome()
driver.get('https://en.wikipedia.org/wiki/Apress')
ActionChains(driver)\
.key_down(Keys.CONTROL)\
.send_keys("a")\
.key_up(Keys.CONTROL)\
.key_down(Keys.CONTROL)\
.send_keys("c")\
.key_up(Keys.CONTROL)\
.perform()
在代码中,您会看到使用 Selenium 中可用的键盘操作选择并复制了 web 页面的所有内容。
向元素发送密钥
在send_keys_to_element
(web_element, send_keys)
中,键被发送到给定函数中的 web 元素,这与只发送键的 send keys 函数不同,因为它没有提到任何元素。
鼠标和键盘动作可以组合起来用于网页上的一个或多个 web 元素。
中止
在pause(secs)
中,动作被延迟(暂停)一段指定的时间(秒)。它在执行操作之前显示一个 web 元素。
重置
reset_actions()
函数清除或删除所有存储的与 web 元素相关的动作。动作可以存储在本地或远程端。
摘要
这一章主要讲述了用户在与网页交互时使用的鼠标和键盘操作。本章从 Selenium 支持的所有鼠标操作开始。然后,演示各种动作及其对应的示例。稍后,您学习了用户可以使用的四个主要键盘功能。
在应用这些操作之前,您需要找到该元素。定位 web 元素的任务由 Selenium 中的 web 定位器完成,这将在下一章讨论。
四、网页元素
在前一章中,您已经了解了鼠标和键盘的基本操作。现在您需要找到一个 web 元素来执行这些操作。本章解释了如何定位 web 元素。有几种类型的 web 元素可用于构建 web 应用。要测试 web 应用,首先需要跟踪其中的 web 元素。元素可以在网页上的任何地方。这些 web 元素可以通过 Selenium WebDriver 提供的定位器来定位或跟踪。
定位器在 web 应用中查找 web 元素;因此,整个章节都致力于 web 元素和定位器。测试用例中还演示了具有内置函数的定位器。在深入研究 web 定位器及其类型之前,让我们从了解什么是 web 元素开始。
元素/Web 元素
元素通常被定义为开始和结束 HTML 标记之间的任何东西。网页或应用由许多不同的元素组成。这些在 web 应用中多次使用的元素被称为 web 元素。
Note
术语元素和 web 元素可以互换使用。
为了避免服务于相同目的的多个 web 元素之间的混淆,使用唯一的属性来区分它们。定义的属性有一个相应的名称,该名称应该是唯一的,作为 web 元素的唯一属性。该属性有助于定位器。
Note
Web 元素可以位于页面上的任何位置。
现在您对 web 元素有了基本的了解。要识别网页上可用的 web 元素,您需要了解定位器。由于每个 web 元素都是不同的,因此有不同的 web 定位器,这将在下面讨论。
网络定位器
网页上至少需要有一个 web 元素,这是使用 web 定位器的一个基本条件。在自动化任何测试之前,您需要在 web 应用或网页中的许多其他元素中识别或找出特定的 web 元素。定位器标识特定的 web 元素。
locator 是 Selenium WebDriver 的一个简单函数或方法。定位器使用 Selenium 支持的不同属性来识别 web 元素。有八个唯一的定位器(函数)来标识 web 元素,下面将对此进行描述。
这些函数提供了跟踪或识别 web 元素以保护脚本的灵活性。让我们看看定位 web 元素的不同方式。
定位元件
网页是使用链接、字段、文本、图像等元素构建的。这些元素在 HTML 中是标签的形式,有时在 HTML 中不是。为了定位这些元素,Selenium 使用定位器。
本章介绍的八种定位器。解释了语法,如何、何时以及在哪里使用这些定位器,使您能够在以后的测试用例中使用它们。
让我们分别看一下这些 web 定位器。
ID 定位器
这种方法或函数是使用最广泛的定位器之一。id 是 HTML 网页中唯一的属性,不太可能受变化的影响。这是在 HTML 页面上定位元素的最简单也是最受欢迎的方法之一。
根据 W3C,每个元素必须有唯一的 ID;然而,浏览器允许这个规则的一个例外。这个异常允许不同的元素具有相同的 ID 名称或者没有 ID,这就是为什么 Selenium 有八个定位器。下面是语法。
var_name = find_element_by_id ('id_attribute')
考虑下面的 HTML 页面源代码。
<html>
<body>
<form id="EmployeeForm">
<input name="employee_name"type="text"/>
<input name="email"type="email"/>
<input name="next"type="submit" value="Login"/>
</form>
</body>
</html>
在 HTML 源代码中,form 标记是唯一具有 ID 属性的元素。表单标签的 ID 属性被命名为EmployeeForm
。使用语法,下面的代码有助于跟踪/查找具有 ID 属性的元素。
Employee_form = driver.find_element_by_id ('EmployeeForm')
通过使用这种方法,如果 ID 属性已知,就可以很容易地定位元素。如果多个元素具有相同的 ID 属性名,则返回第一个匹配的 ID。如果不匹配,则调用异常。这种异常称为 NoSuchElementException。
名称定位器
一个元素可能有多个关联的属性。name 属性是一个广泛使用的属性,但它可能是也可能不是唯一定义的。name 属性通常是表单上的输入元素(但也用于文本字段和按钮中)。在表单上执行提交操作时,name 属性将所有相应的值传递给服务器。
var_name = find_element_by_name ('name_attribute')
下面的 HTML 源代码显示了如何定位具有 name 属性的元素。
<html>
<body>
<form id="EmployeeForm">
<input name="employee_name" type="text" /><!--1st element-->
<input name="email" type="email" /><!--2nd element-->
<input name="next" type="submit" value="Login" /><!--3rd element-->
<input name="next" type="button" value="Clear" /><!--4th element-->
</form>
</body>
</html>
有两个带有名称属性的输入标签。第一个和第二个输入标签(元素)以employee_name
作为名称属性,电子邮件元素很容易定位,如下所示。
#Locating first element
employee = driver.find_element_by_name('employee_name')
#Locating second element
email = driver.find_element_by_name('email')
在每种情况下,名称定位器都与 HTML 源页面上的第一个元素匹配。如果页面上没有匹配的元素,则调用 NoSuchElementException。
在多个元素具有相同名称作为属性的情况下,定位器选择 HTML 页面上具有确切指定名称的第一个元素。
next = driver.find_element_by_name('next')
在前面的方法中,返回登录按钮,因为它出现在清除按钮之前。要从一个页面返回多个元素,请参考“定位元素”一节。
XPath 定位器
XML 语言中使用 XPath 来定位通过元素和属性导航的节点。路径由与特定节点相关联的表达式组成。HTML 也支持使用 XHTML 实现 XML。在没有 ID 和名称的情况下,很难定位元素。在这些情况下,XPaths 定位器通过链接来识别元素。它是仅次于 ID 和名称的第三大常用定位器。有几种方法可以定位链接,因为它们是树状结构。
XPath 的一般语法是
-
//
:定义当前目录/标签(单斜线表示绝对路径) -
tag_name
:定义指定路径的标签名称 -
@
:指定要选择的属性 -
attribute_name
:指定属性的名称;节点属性的名称 -
值:定义指定属性的值
xpath =//tag_name[@attribute_name= 'value']
为了更好地理解 Xpath,您需要了解 XML 文档。XML 文档是树形结构,具有各种相关的属性和标签。下面以 XML 文档的形式显示了雇员的树形结构。
<employee>
<department = "Testing">
<fname>John </fname>
<lname>Wick</lname>
<title>Senior Tester</title>
<salary>$10000</salary>
</department>
<department = "Development">
<fname>Harry</fname>
<lname>Potter</lname>
<title>Junior Developer</title>
<salary>$5000</salary>
</department>
</employee>
节点形成树状结构。这些节点有一个根节点,DOM 结构就是从这个根节点开始的。其他节点被视为叶节点或子节点。
Note
根节点也称为父节点、起始节点或初始节点。
XML 文档结构如图 4-1 所示。
图 4-1
XML 文档结构的文档对象模型
XML 文档只包含一个根 web 元素,它是一个雇员。employee web 元素有两个节点作为部门:测试和开发。这些部门也被称为根元素的属性。
每个部门包含另外四个属性:fname、lname、title 和 salary。这四个属性与它们各自的值相关联。测试部门雇员的值如下:fname 是 John,lname 是 Wick,title 是 Senior Tester,salary 是$10000。同样,对于开发部门,值为哈利、波特、初级开发人员和 5000 美元。
以下 XML 页面源由各种标记和属性组成。您还需要了解一些术语,这将在接下来的章节中介绍。
节点
在网页中,树状结构表示 DOM。节点从结构的起点到终点相互连接。初始节点被称为根节点。它有时被称为初始节点。
在 HTML 中,<html>
标签是根节点或节点开始的初始节点。
双亲
嵌入在开始和结束标记之间的 web 元素有一个关联的父元素。除了根节点之外,任何元素都至少有一个父元素。head 和 body 标签有一个 HTML 标签作为父标签,这是一个根元素。
孩子们
父元素可以有一个或多个子元素。head、body 和 div 标签有与其相关联的子标签。有时,父标签没有子标签,例如 title 标签。
同科
属于同一父元素的 web 元素被称为兄弟元素。例如,div 标签中的所有标签都是兄弟标签。
原子值
没有父元素或子元素的 web 元素被称为原子值。最好的例子是没有子节点的根节点。
XPath 方法
XPath 轴通过使用与 XML 中相同的结构树机制来帮助导航或定位 web 元素。web 元素的动态特性使得定位 XPath 变得困难,因此 axes 方法解决了这个问题。
XPath 轴有 13 种不同的方法来定位复杂或动态的 web 元素。
儿童
它定位与网页/应用上的当前或所选 web 元素相关联的所有可用子元素。
父母
它定位当前 web 元素的父元素。如果当前元素没有任何父元素,则根节点被视为其父元素。根元素是所有可用元素的父元素。
自轴
它只检测一个 web 元素(即自身)。
祖先
它定位从当前元素的父元素开始到其所有可用祖先(即,父元素、祖父元素、曾祖父元素等)的所有 web 元素。).它包含根元素,除非它是根元素。
祖先或自我
在这种情况下,将定位所选 web 元素的所有可用祖先,包括当前元素。
后裔
它定位所有子 web 元素。后代包括当前元素的子元素和孙元素。
后代还是自己
它包括当前元素及其所有子元素。如果没有子元素,那么只返回当前元素。
跟随
它定位当前元素之后的所有 web 元素。它不包括当前元素。
跟随兄弟姐妹
它将所有 web 元素定位在当前元素之后的同一级别。例如,任何选择框或单选按钮元素。
在前的
它定位出现在页面上当前元素之前的所有 web 元素。
前面的兄弟姐妹
它定位出现在同一级别的选定元素之前的所有同级元素。
属性
使用属性定位 web 元素后,将检查指定元素的该属性。如果匹配,则返回该元素;否则,它返回一个空值。
命名空间
它定位与名称空间相关联的所有 web 元素。这是最少使用的 XPath 轴之一。
Note
没有子元素(即()
)的 web 元素被称为叶节点。
节点示例
下面的 HTML 定义了一个结构及其关系。这种关系如图 4-2 所示。
图 4-2
HTML 标签之间的关系
<html><!-- Root node-->
<head><!-- Parent -->
<!--Child of head tag-->
<title></title>
</head>
<body><!-- Parent -->
<!--<div>Child of body
And Parent of header, section, aside, footer -->
<div>
<!—Child one-->
<header>
</header>
<!—Child two-->
<section>
</section>
<!—Child three-->
<aside>
</aside>
<!—Child four-->
<footer>
</footer>
<!-- The four tags header, section,
aside and footer are siblings to each other -->
</div>
</body>
</html><!-- End Node -->
根节点或开始节点是初始的 HTML 标签。HTML 标签有两个子元素:head 和 body。头只有一个子元素标题。head 分别是 HTML 标签的子标签和标题的父标签。head 和 body 标签是兄弟。
类似地,body 有一个子元素:div。div 标签有四个子标签。div 是 body 标记的子元素,是四个子元素的父元素:header、section、side 和 footer。这四个元素是兄弟元素,没有任何自己的子元素。div 标记没有同级。
HTML 是所有元素的祖先。同样,头部和身体只是它们的子元素的祖先。title 和 div 元素是 HTML 元素的子元素。这个头没有孙子。身体有四个孙辈。子代(ren)和孙代(ren)分别是父代和祖父代的后代。同样,父元素是子元素(ren)和孙元素(ren)的祖先。
标头是其他三个兄弟的前一个兄弟。页脚是前三个同级的下一个同级。同样,头部和身体分别是前面和后面的兄弟。
Note
XPath 依赖于浏览器,因为每个浏览器的行为都不同。
XPath 定位器类型
XPath 中有两种定位器可以用来在 Selenium 中定位 web 元素。接下来将讨论它们。
绝对路径
绝对路径是一种直接定位 web 元素的方法。它是最简单的 XPath,存在于 DOM 结构中。如果在此路径中进行了任何更改,web 元素将无法定位元素。绝对路径是 web 元素可用的路径。
绝对路径从根节点(即初始节点)开始。节点之间的连接由单个正斜杠(/
)表示。该路径按照从顶层节点开始的分层顺序排列。
考虑下面的 HTML 代码,它显示了绝对路径是如何导出的。
<html>
<title></title>
<head></head>
<body>
<form id="EmployeeLogin">
<input name="fname" type="text" value="First Name"/><!--Input1-->
<input name="lname" type="text" value="Last Name"/><!--Input2-->
<input name="email" type="text" value="Email"/><!--Input3-->
<input type="text" name="location" value="Location"><!--Input4-->
<input name="password" type="password"/><!--Input5-->
<input name="continue" type="submit"
value="Employee Login"/> <!--Input6-->
</form>
</body>
</html>
绝对路径定位 HTML 代码中位置字段的输入。输入字段位于数字 4 的位置,所以它的绝对路径是
form_element= driver.find_element_by_xpath
("/html/body/form/input[4]")
Note
在 Selenium 中,索引从 1 而不是 0 开始。
在前面的绝对路径中,路径从根节点(即 HTML 节点)开始,到 input[4]节点结束,input[4]节点是要定位的 web 元素。这里所需的 web 元素是 location 字段,它位于所描述路径的结束节点。
Note
绝对路径从根节点开始,到需要定位的节点结束。
相对路径
在相对路径中,web 元素位于 DOM 结构中,这使得它不太容易被更改。相对路径比绝对路径更有助于定位 web 元素。
XPath 可以从 web 页面中的任何地方开始(即 DOM 结构),在 web 元素需要定位的节点处结束。节点之间用双斜线(//
)分隔,而不是单斜线。
Note
在相对路径中,当前目录作为参考。
相对路径使用比绝对路径更短的路径来定位 web 元素。如前面的 HTML 代码所述,要定位位置字段,其相对路径如下。
form_element= driver.find_element_by_xpath
("//form//input[4]")
这里,节点从表单元素开始,到第四个输入字段结束。末端是要定位的元素。
Note
斜线很容易区分绝对路径和相对路径。在 Xpath 中,单斜线表示绝对路径,双斜线表示相对路径。
带有逻辑运算符的 XPath
带有逻辑运算符的 XPath 表达式允许您在网页上检查或定位多个 web 元素。逻辑运算符也称为布尔运算符,因为它可能会也可能不会返回指定的元素。web 元素使用逻辑运算符至少需要两个 XPath 表达式,因此一个逻辑运算符可以定位一个或多个 web 元素。web 元素的返回取决于指定的条件。
指定条件的结果为真或假。当结果为真时,它返回一个 web 元素,否则不返回任何元素。下面描述两个主要的逻辑运算符。
和
当两个 XPath 指定的属性匹配或在给定网页上可用(存在)时,AND 逻辑运算符返回或定位 web 元素;否则,它不返回任何 web 元素。如果 web 元素或其属性不可用,则会发生 NoElementFoundException。and
是该运算符使用的关键字。
form_element=driver.find_element_by_xpath("//input[@name='fname'
and @type='text']")
在该示例中,当输入 web 元素匹配与其关联的名称和类型属性时,将返回该元素。表 4-1 显示了元素的位置。
表 4-1
Web 元素结果的条件
|A
|
B
|
结果
|
| --- | --- | --- |
| 错误的 | 错误的 | 未找到元素 |
| 真实的 | 错误的 | 未找到元素 |
| 错误的 | 真实的 | 未找到元素 |
| 真实的 | 真实的 | 定位两个元素(A&B) |
类似地,当使用 AND 逻辑运算符通过指定两个相关属性来返回多个 web 元素时,它将返回一个 False 值。当属性属于不同的元素时,这可以被验证并实现。下面是另一个展示 XPath 返回多个 web 元素的例子。
form_elements=driver.find_elements_by_xpath("//input[@name='fname'and @name='lname']")
两个 web 元素通过它们的名称属性来定位。
运筹学
在这种逻辑运算符类型中,当两个指定属性或 web 元素中的任何一个在网页上可用时,它仅返回真布尔值的 web 元素。当两个条件都为假时,它不返回任何元素。关键词是or
。下面是一个简单的例子,其中使用 or 逻辑运算符检查输入表单的属性。
form_elements=driver.find_elements_by_xpath("//input[@name='fname'] or
[@name='newpassword']")
此示例检查与输入表单相关联的两个属性——名称和类型。如果任何属性属于所述的任何输入表单,那么它返回相应的 web 元素。在这种情况下,将返回第一个输入框(Input1 ),但是没有类型为newpassword
name 属性的输入表单。
表 4-2 显示了网络元素的逻辑值。
表 4-2
或带有 Web 元素结果的条件
|A
|
B
|
结果
|
| --- | --- | --- |
| 错误的 | 错误的 | 未找到元素 |
| 真实的 | 错误的 | 定位元素 a |
| 错误的 | 真实的 | 定位元素 b |
| 真实的 | 真实的 | 定位两个元素(A&B) |
类似地,输入表单的三个不同属性也提到了or
逻辑操作符。比较的 web 元素的属性是名称和类型。所有属性都属于给定输入表单中的每个不同的 web 元素;因此,它返回所有相关的输入表单。
form_elements=driver.find_elements_by_xpath("//input[@name='fname'] or
[@name='lname'] or [@type='email']")
在or
逻辑代码片段中,从一到三的前三个输入表单作为结果被检索。逻辑操作符的使用在 Selenium 中不受限制,因此可以用于多个 web 元素。
Note
两个逻辑运算符都区分大小写(即and
、or
)。
XPath 函数的类型
在一个 web 应用/页面中有许多 web 元素,这会使定位具有相同属性的元素成为问题;例如,具有相同属性的几个按钮,如名称或 id。为了定位这些 web 元素,Selenium 提供了 Xpath 函数。优选地,这些功能与动态变化的 web 元素一起使用。接下来讨论一些常用的 XPath 函数。
包含( )
contains()
是一种用于动态改变与 HTML 页面中的 web 元素相关联的属性中的值的方法。当您知道 XPath 中实现的部分属性值或部分链接文本时,可以使用它。contains()
函数在网页上搜索给定的文本,如果匹配就返回 web 元素。它通常用于登录页面,其中登录 ID 会动态变化。
contains()
函数的语法是
//xpath[contains(@attribute, 'attribute value')]
下面是contains()
在完整和部分文本中的例子。
//with complete text
element1 =driver.find_elements_by_xpath("//input[contains(@id, 'fname']")
//with Partial Link
element2 =driver.find_elements_by_xpath("//input[contains(@name, 'pass']")
使用我们之前的表单 HTML 示例,这个代码片段中的 web 元素搜索文本并为element1
返回 input1,为element2
返回 input5。你需要明白,element2
被提供了部分文本(pass
’),它匹配表单输入的 name 属性(password
’)。因此,部分文本允许您定位动态 web 元素。
文本( )
在 web 元素缺少属性的情况下,text()
函数允许您通过识别某些文本来定位元素。具有该文本的 web 元素被定位。
//xpath[text() = 'login-in']
下面的 html 代码片段使用text()
函数来跟踪 web 元素。
<button type="button"> Submit <button/>
element3 =driver.find_elements_by_xpath("//button[text() = 'Submit']")
按钮标记没有属性;它只有相关的文本。text()
函数用于定位该元素。element3
检索带有与其相关的'submit'
文本的按钮。
以( )开头
该函数非常类似于 contains 函数;唯一的区别是,它从检查 XPath 之后提供的初始字符串开始。这个函数非常适合那些在页面重新加载后值会发生变化的 web 元素。匹配初始字符串或文本以定位 web 元素。
下面是一个通用语法示例。
//xpath[starts-with(@attribute, 'attribute value')]
element4 =driver.find_elements_by_xpath("//form[starts-with(@id, 'Employee']")
element4
的字符串id
是初始值,与页面上可用的表单 ID 相匹配。
CSS 选择器
CSS 选择器和 XPath 是相似的,因为它们都可以检测网页上复杂的 web 元素。CSS 选择器比 XPath 更容易实现,因为 CSS 与 DOM 无关,并且在定位 web 元素时更加灵活。当一个网页集成了很多 CSS 时,使用 CSS 选择器来定位网页元素是很容易的。它也很健壮。
Note
CSS 是级联样式表的首字母缩写。这是使 HTML 页面具有吸引力的主要因素。
CSS 选择器是由一个元素选择器和它对应的值组合而成的。这个对应的值定位或标识页面中的 web 元素。该值可以是 ID、标签、属性值等形式。
当 CSS 选择器用于定位 web 元素时,当与指定的属性匹配时,将返回网页中的第一个元素。如果没有元素符合指定的条件,则会引发异常。CSS 选择器的一般语法是
find_element_by_css_selector()
以下方法展示了一些与用于定位 web 元素的 CSS 选择器相关的格式。
身份
当 CSS 选择器与 ID 属性一起使用时,在 HTML 标签和 ID 属性之间放置一个散列(#
)符号。该符号仅用于 ID 属性。带有 ID 属性的 CSS 的一般语法是
<HTML_tag>#<ID_value>
这是 HTML 的例子。
<pid="press">Apress Publication </p>
您可以使用 CSS ID 定位器来定位 web 元素。
press=driver.find_element_by_css_selector('p#press')
有几种不同的方法可以用来代替前面的脚本,同样也可以定位 web 元素。
press=driver.find_element_by_css_selector("p[id = 'press']")
press=driver.find_element_by_css_selector("p#id='press'")
班级
CSS 选择器可以和 class 属性一起使用来定位 web 元素。HTML 标签和 class 属性之间使用了一个点(.
)。带有类的 CSS 的语法是
<HTML_tag>.<class_name>
在下面的 html 代码片段中,CSS 选择器定位段落元素。
<html>
<body>
<p class="press ">Apress Publication </p>
//HTML tag with multiple CSS classes
<p class="my-class text-justify">New York</p>
</body>
</html>
press=driver.find_element_by_css_selector('p.press')
'press'
变量使用 CSS 定位器定位 web 元素。一个点符号(.
)将多个类组合成一个 CSS 选择器。它还区分了属性和值。
类似地,您可以找到具有多个 CSS 类的 web 元素。以下是写这个的各种方法。
press1 =driver.find_element_by_css_selector('p.container')
press1 =driver.find_element_by_css_selector('p.my_class')
press1 =driver.find_element_by_css_selector('.my_class')
press1 =driver.find_element_by_css_selector('my_class.container')
press1 =driver.find_element_by_css_selector('container.p')
所有 CSS 定位器脚本返回相同的 web 元素。
子字符串匹配大小写
Web 元素可以具有动态属性,并且对于不时出现的某些实例,往往会发生变化。要定位这些元素,默认 CSS 不是一个选项,因为它使用静态值作为 ID、类和名称。
CSS 选择器接受的符号在表 4-3 中描述。
表 4-4
带语法的元素定位器
|元素定位器
|
句法
|
| --- | --- |
| 身份 | 按标识查找元素( ) |
| 名字 | 按名称查找元素( ) |
| 路径语言 | find_element_by_xpath() |
| 环 | find_element_by_link_text() |
| 部分链接 | find _ element _ by _ partial _ link _ text() |
| 标签名称 | 按标签名查找元素( ) |
| 类别名 | find_element_by_class_name() |
| CSS 选择器 | find_element_by_css_selector() |
表 4-3
带描述的子串字符
|标志
|
字符名称
|
描述
|
| --- | --- | --- |
| ^ | 停止 | 匹配字符串的前缀 |
| $ | 美元 | 匹配字符串的后缀 |
| * | 星号 | 使用子字符串匹配字符串 |
| : | 结肠 | 使用 contain()方法匹配字符串 |
所有的 substring 方法都应用在下面的 html 脚本片段中。这些子字符串与表 4-3 中描述的 id 相匹配。
<p id="apress_press"></p>
<p id="apress_123"></p>
<p id="123_apress_press"></p>
下面显示了使用子字符串定位的 CSS 选择器。
#Using Halt '^' for suffix
press3 =driver.find_element_by_css_selector("p[id^='123']")
#Using Dollar '$' for prefix
press3 =driver.find_element_by_css_selector("p[id$='press']")
#Using Asterisk '*' for all
press3 =driver.find_element_by_css_selector("p[id* ='_apress_']")
#Using Colon ':' for contain method
press3 =driver.find_element_by_css_selector("p:contains('_apress_')")
当测试人员不知道完整的字符串模式时,这四个 substring 方法非常重要。
内部文本
带有contains()
功能的冒号字符可以通过匹配 HTML 标签之间的文本来检索 web 元素。这段文字叫做内文。
这个方法匹配开始和结束 HTML 标记之间的纯文本。使用页面上任何地方的文本来定位元素,这与所讨论的子字符串中的contain()
函数相同。
<p>Apress</p>
press5 =driver.find_element_by_css_selector("p:contains('Apress')")
函数是用返回包含它的 web 元素的文本编写的。文本可以是完整的,也可以是部分的。
多个属性的 CSS 选择器
有时很难找到具有单一属性的 web 元素,因为不同的 web 元素具有相同的属性值。这可以通过使用 CSS Locator 和与特定 web 元素相关联的多个属性来解决。
以下是 HTML 代码示例。
<p class ="container" id="apress" style="align-self: center;"></p>
下面是选择器的运行情况。
press4 =driver.find_element_by_css_selector("p[class= 'container'][id='apress'][style='align-self:center']")
在这个代码片段中,声明了多个属性及其关联的 tag 值来定位它。
子元素的 CSS 选择器
与 XPath 中讨论的子元素一样,CSS 选择器也可以在网页上定位子元素。为了识别或定位子元素,Selenium 提供了与 CSS 选择器一起使用的特殊符号。
如果 web 元素有一个子元素,那么使用大于号(>
),其中 XPath 使用斜杠。
<div class="cars">
<button id=Aston>
</div>
前面是带有一个子元素的 web 元素的示例。HTML 是div.cars>a
,其中div
是父节点,button
是它唯一的子节点。
这是 HTML 示例。
<div id="cars">
<a href="#aston_martin">Aston</a>
</div>
XPath 使用//div//a
来定位 web 元素,而 CSS 选择器使用空格而不是斜线。
cars = driver.find_element_by_css_selector("div#cars a")
当存在多个没有 ID 或名称的子元素时,通过索引定位元素,也称为第个元素类型。它允许定位索引元素。索引从 1 开始。
<ol id="cars">
<li>Aston Martin</li>
<li>BMW</li>
<li>Chevy</li>
<li>Dodge</li>
</ol>
这个有序列表有四个没有相应属性的子元素。为了定位这些元素,需要建立索引(从一个元素开始)。要定位的元素是第二、第三和第四个元素。
以下代码显示了使用 CSS 选择器定位的子元素。
#Locating second child element
car_no2 =driver.find_element_by_css_selector("ul#carsli:nth-of-type(2)")
#Locating third child element
car_no3 =driver.find_element_by_css_selector("ul#carsli:nth-of-type(3)")
#Locating last child element
last_cars=driver.find_element_by_css_selector("ul#carsli:last-child")
假设一个元素有 n 个子元素,而你不知道与之关联的子元素的数量。在这种情况下,后跟'last-child'
关键字的 HTML 属性用于定位父元素的最后一个子元素。
链接定位器
链接文本定位器用于定位锚标签(<a>
) .
中可用的 web 元素,锚标签总是定义一个从一个页面切换到另一个页面的链接,也称为超链接。anchor 标签中的href
属性指定了页面迁移到的目的地。
链接文本定位器试图匹配与锚定标签相关联的网页上可用的精确文本。链接文本定位器的语法是
find_element_by_link_text()
Note
通常,click()函数访问网页/应用中的链接。
HTML 代码中有链接定位器定位的锚标记。HTML 是
<div class="container">Categories
<a href="python.html">Python</a>
<a href="web.html">Web Development</a>
<a href="machine.html">Machine Learning</a>
<a href="databases.html">Database</a>
</div>
网络驱动链接文本定位器定位分别与 python.html 和 database.html 的目的地地址相关联的文本 Python 或数据库。
# Locate elements using link text
link1 =driver.find_element_by_link_text("Python")
link2 =driver.find_element_by_link_text("Database")
当锚标记中有多个具有相同文本的元素时,链接定位器检索第一个匹配的元素。
Note
链接文本和部分链接定位器都区分大小写。
部分链接定位器
这种部分链接定位器非常类似于链接定位器。唯一的区别是部分链接定位器试图匹配网页上锚标签中文本的子字符串。语法是
find_element_by_partial_link_text()
Note
使用两个链接定位器中的任何一个都可以访问任何链接,不管锚标记是在块 web 元素之内还是之外。
以下是相同 HTML 锚标记的部分文本 Python 代码。
# Locate elements using partial link text
link3 =driver.find_element_by_partial_link_text("Pyt")
link4 =driver.find_element_by_patial_link_text("Data")
Pyt 和 Data 是 Selenium WebDriver 的部分文本,用于定位锚标签内的元素。部分文本与网页上显示的文本相匹配;匹配时,它返回相关元素。类似地,当文本与多个 web 元素匹配时,第一个元素作为结果返回。
Note
当多个 web 元素出现在链接文本/部分链接文本定位器中定义了相同文本的网页上时,XPath 或 CSS 选择器用于定位其他 web 元素。
标签名称
一个网页/应用由许多 HTML 标签组成。这些标签因元素而异,但是允许在不同的 web 元素上使用相同的标签。在某些情况下,标签使您能够定位所选择的 web 元素。标记名的语法是
find_element_by_tag_name()
以下是相关 HTML 标记的标记名。
<html>
<head>
<title>Apress</title>
</head>
<body>
<h1>Python with Selenium</h1>
</body>
</html>
Selenium 标签名称定位器是
#Locating web element having <Title> tag
tag1 =driver.find_element_by_tag_name('Title')
#Locating web element having <h1> tag
tag2 =driver.find_element_by_tag_name('h1')
当一个页面上有多个具有相同标签的 web 元素时,Selenium WebDriver 会定位第一个匹配指定标签的 web 元素。如果没有名为 title 或 h1 的元素,则会引发 no element 异常。
类别名
类名用于定位 web 元素,方法是在 Selenium 提供的类函数中声明类名。在 HTML 标记中很容易提供类名。类名定位器不是定位 web 元素的首选方式。语法是
find_element_by_class_name()
下面是一个简单的带有 Python 类名定位器的 HTML 示例。
<html>
<body>
<div class="my-class">Apress
<p class="text-justify">Python with Selenium</p>
</div>
</body>
<html>
下面是 Python 代码。
#For div element
class1 =driver.find_element_by_class_name('my_class')
#For paragraph Element
class2 =driver.find_element_by_class_name('text-justify')
与多个元素的其他 web 定位器行为一样,类定位器返回同一类中许多其他元素中第一个匹配的 web 元素。当没有匹配的元素时,将引发异常。表 4-4 中给出了所有讨论过的定位器的语法。
Note
当 web 定位器无法定位 web 元素时,会引发 NoSuchElementException。
定位多个 Web 元素
当多个 web 元素具有相同的名称/ID/text/tag/class/link 时,Selenium WebDriver 将返回第一个匹配的元素。为了定位页面上所有可用的元素,Selenium 为每个定位器提供了一个函数/方法。每个定位器的语法在表 4-5 中列出。
表 4-5
定位所有 Web 元素的语法
|元素定位器
|
句法
|
| --- | --- |
| 身份 | find_elements_by_id() |
| 名字 | 按名称查找元素( ) |
| 路径语言 | find_elements_by_xpath() |
| 环 | find_elements_by_link_text() |
| 部分链接 | find _ elements _ by _ partial _ link _ text() |
| 标签名称 | find_elements_by_tag_name() |
| 类别名 | find_elements_by_class_name() |
| CSS 选择器 | find _ elements _ by _ css _ selector() |
定位器返回的数据类型是列表。下面的例子列出了使用 CSS 选择器找到的所有元素。
import requests
from selenium import webdriver
driver = webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
driver.get('https://apress.com')
images = driver.find_elements_by_css_selector("img")
for image in images:
if (requests.head(image.get_attribute('src')).status_code == 200):
print("Element Found.")
列表中返回的所有元素都在循环中打印。定位器列出了 press 网页上所有可用的 web 元素。
定位器问题
存在 web 定位器无法定位元素的情况。接下来讨论定位器的常见问题。
属性变化
当对 web 元素执行某些操作时,它的行为总是会发生变化。这些动作可能是重复的,也可能每次都是新的。动态 web 元素开发了一种复杂的体验。一个例子是,像鼠标点击或页面重新加载这样的用户事件每次都可能导致不同的属性值。属性值的这些更改可能会阻止定位所需的 web 元素。要定位这些 web 元素,您必须确保定位器返回与其相关的 web 元素,不管发生了什么变化。
默认属性也由在网页/应用的内部框架中实现它们的开发者来改变。这使得能够分解页面上与该属性相关联的默认 XPath。要修正此类更改,您需要选择不同的定位器或再次检查路径。
没有 Web 元素
在许多情况下,web 元素是在某个事件发生或动作完成时创建的。只有在单击注销按钮后,注销元素才可用。类似地,在用户执行翻转或点击动作之后,菜单中的元素是可用的。
在这些情况下,事件会触发 web 元素的创建,因此必须在使用定位器之前执行操作。
Web 元素不可见
Web 元素在页面重新加载或用户执行操作后变得可用或可见,这就像没有 web 元素一样,但 web 元素存在于页面上。当应用定位器并且定位器不可见时,Selenium WebDriver 返回一个 NoElementFound 错误。
为了避免这些错误,web 元素通过等待变得可见,然后可以定位它们。有时 AJAX 脚本被用来隐藏元素,这些元素是使用等待来定位的。等待在第十章中解释。
测试用例不匹配
在某些时候,测试用例与定位器条件不匹配,或者测试用例的执行速度比 web 应用快,从而导致没有找到 Web 元素的错误。这是因为测试用例与 web 应用没有同步创建或显示 web 元素。
为了解决测试用例与网页/应用之间的同步丢失,测试用例暂停,直到满足所需的条件,这使得网页上的 web 元素可用。
iframe Web 元素
当一个 web 元素是一个 iframe,或者 iframe 中有一个元素时,定位这些元素就变得很困难,因为框架不容易访问。当有多个帧可用时,识别特定帧并不容易。即使它们可用,定位器也无法定位这些帧并返回错误。
要定位 iframe 或其中的元素,您需要识别页面上所有可用的框架,然后使用switchTo.frame()
函数切换到要定位的框架。切换到指定的帧后,您可以使用任何定位器来定位 web 元素。
摘要
本章讨论了几种 web 定位器。ID 和名称定位器是最常用的,因为它们不容易被更改。下一个重要的定位器是 XPath。您看到了 XML 文档中 XPath 的结构。CSS 定位器是本章介绍的另一个重要的定位器。
下一章研究使用本章中讨论的定位器来定位超链接 web 元素。
五、导航
在上一章中,我们回顾了网页上可用的各种导航链接,这些链接可以使用 web 定位器来定位。还讨论了一些功能和特性。本章介绍了用于查找导航元素的 web 定位器应用。
在 web 开发中,超链接或链接是对数据的引用。这些数据以文档、视频、图像等形式嵌入到 web 元素中。导航可以定义为从一个位置迁移到另一个位置的活动。这种迁移可以在网页内进行,也可以在包含 web 元素的另一个网页上进行。导航过程是使用超链接完成的。
链接是显示在网页上的 URL(统一资源定位符),而超链接是通过在 HTML 中出现的锚标记之间放置链接来创建的。本章描述了定位超链接的各种方法,并设置了标准来测试其在嵌入了不同 web 元素的网页上的存在性。
用一个编程示例说明了定位超链接的机制。在网页导航的上下文中,您将了解超链接以及它们在网页上是如何定义的。
超链接
超链接主要与菜单、按钮、图像和文档相关联,通过使用鼠标动作(如单击)或提交表单,将用户引导到当前网页或另一个网页上的新位置/部分。在少数情况下,当表单完成时,按钮内会提供一个超链接来导航。
在网页上使用超链接有多种方式。超链接被合并到一个 HTML 锚标签中,该标签以<a>
开始,以。任何文本都可以写在锚定标签中。该文本在浏览器中以默认的蓝色显示。超链接也被称为链接,可以使用 CSS 进行修改。语法是
<a href="URL">link text</a>
Note
超链接也被称为链接。
下面是一个 HTML 的例子。
<div class="container">Selenium
<a href="python.html" id="python">Python</a>
<a href="elements.html" id="elements">Elements</a>
<a href="driver.html" id="driver">Driver</a><!—nth element➤
</div>
现在您已经了解了超链接,让我们看看如何在 Selenium 中使用 Python 测试它们。
测试超链接
Selenium 测试用例检查超链接是否断开。由于服务器错误,断开的链接不可达或不起作用。超链接是连接不同网页及其相关元素的媒介。
可以测试超链接的以下几点。
-
链接是否可用
-
通过从 HTTP 获取响应,链接是否正确导航到指定页面(断开的链接)
-
对于依赖超链接的文档上传和表单提交
-
网页上的许多链接使得手工测试非常耗时
Note
链接文本显示网页上超链接的存在。
Web 定位器提供了定位超链接的垫脚石。下面讨论定位超链接的各种方法。
按 ID 的超链接
可以使用锚标记中可用的 ID 来定位超链接。当网页有多种语言版本时,ID 是定位未更改的超链接的最佳方式。当找到超链接时,需要点击它来导航。
link1 =driver.find_element_by_id("python")
文本超链接
此语法匹配为链接指定的完整字符串。字符串可以是除英语之外的任何语言,英语有时会返回一个名为 NoSuchElementFound 的异常。
link2 =driver.find_element_by_link_text("Python")
部分链接的超链接
当需要在部分字符串中定位链接时,使用部分链接语法。该字符串与链接中存在的子字符串匹配。
# Locate elements using partial link text
link3 =driver.find_element_by_partial_link_text("Pyt")
XPath 超链接
可以使用 XPath 定位链接(参见第四章),如下所示。
link4 =driver.find_element_by_xpath("//a[@id= 'python']")
第 N 个超链接
当网页上有多个链接时,您可以使用索引值来选择链接。当需要使用索引时,链接应该在同一个标签下并按顺序排列。链接位于无法使用索引值识别或跟踪的标签下,因为标签会发生变化。
link5 = driver.find_element_by_xpath("//div/a[3]")
当链接的位置改变时,索引值也会改变,因此这种方法不太常用。
Note
添加或删除链接也会改变当前的索引值。
到目前为止,我们仅使用各种 web 定位器定位单个超链接。如果网页上有多个超链接,那么这些方法只返回其中第一个匹配的超链接。要定位所有 web 元素,请参考第四章中的表 4-5。
返回所有超链接
当一个网页上有多个链接时,CSS 选择器用于返回所有的链接。
links=driver.find_elements_by_css_selector("a")
在对超链接进行任何检查或验证之前,需要通过不同的定位器对其进行定位。要检查网页上是否存在超链接,可以使用验证表达式测试链接,这将在下面讨论。
检查有效的超链接
使用 HTTP 状态代码值来验证超链接是否有效。HTTP 发回一条对应于这些值的消息(见表 5-1 )。当链接断开时,HTTP 返回 404 错误(未找到链接或页面错误)。
表 5-1
HTTP 状态代码
|HTTP 代码
|
描述
|
| --- | --- |
| Two hundred | 有效链接 |
| four hundred | 错误的请求 |
| Four hundred and one | 未经授权的 |
| Four hundred and four | 找不到链接/页面 |
| Five hundred | 内部错误 |
import requests
from selenium import webdriver
driver=webdriver.Firefox()
driver.get("http://apress.com/")
links=driver.find_elements_by_css_selector("a")
for link in links:
if (requests.head(link.get_attribute('href')).status_code==200):
print("Link is Valid")
else:
print("Link is Invalid/Broken")
类似地,您可以通过将 CSS 选择器值更改为img
来检查图像。
HTTP 状态代码及其错误描述在表 5-1 中列出。
检查损坏的图像
链接也可以与图像相关联。还可以通过与 HTTP 状态代码进行比较来检查超链接图像是否损坏,就像在只有链接的情况下一样。
import requests
from selenium import webdriver
driver =webdriver.Firefox()
driver.get("http://apress.com/")
images=driver.find_elements_by_css_selector("img")
for image in images:
if (requests.head(imageget_attribute('src')).status_code==200):
print("Valid Image Link.")
else:
print("Invalid Image Link.")
可以使用 HTTP 协议中可用的状态代码来验证超链接(见表 5-1 )。现在,您已经知道了如何基于这些协议来验证超链接的存在,让我们来检查与超链接相关联的各个数据属性。
数据属性超链接
data 属性返回链接的文本值。当超链接元素未知时,该命令可以获取与超链接元素相关的数据属性值。
下面是一个 HTML 的例子。
<div class="hyper_links"><a href="python.html">Python</a></div>
下面是一个 Python 示例。
link1 =driver.find_element_by_css_selector("div.hyper_links a")
print (link1.text)
这个测试用例返回 Python 中的数据属性,这是锚标记之间的一个属性文本值。
Note
表单或文档上载有与之相关的动态超链接。
摘要
本章定义了超链接,它对于迁移到网页上的另一部分或新网页至关重要。本章还介绍了测试超链接的主要方面以及定位超链接的不同方法。您了解了如何在网页上定位多个超链接。可以在超链接上执行许多验证。验证基于 HTTP 状态代码。
是时候探索更多可以定位和验证的独特的 web 元素了,比如超链接。由于选择的方法不同,验证有点独特。你将在下一章学习按钮。
六、按钮
用于跳转到 web 应用不同部分或页面的超链接定位器在上一章已经讨论过了。相同的 web 定位器用于跟踪按钮等用户界面元素。web 应用中有各种按钮,本章对此进行了介绍。
在任何与用户/客户端交互的 web 应用中,按钮都是用户界面的一部分。这些交互与特定的操作相关联,例如移动到下一页和提交表单。它们包括默认按钮、表单/提交按钮、单选按钮、复选框和选择列表。它们之间的差异取决于用法,这将在下面解释。
使用 Python 在 Selenium 上定位 HTML 按钮的类型,因为像这些按钮这样的 web 元素具有与之相关的特定功能。让我们从了解网页上的默认按钮开始。
默认按钮
默认按钮是 HTML 网页上最基本的类型。使用<button>
标签创建一个默认按钮。下面的代码片段允许您创建一个默认按钮。图 6-1 显示输出。
图 6-1
默认按钮
<button id="default_btn" class="default" name="dft_btn" style="font-size:21px;">Default Button</button>
默认按钮可以具有各种功能,例如编辑、删除、创建、重置和清除。Selenium 在按钮上执行两个主要操作。
-
选择(定位元素并单击)
-
断言(检查按钮以及是否启用/禁用)
挑选
选择并单击按钮是在网页上定位按钮元素的一种方式。一个按钮在被点击时被激活,然后它执行分配给它的任务。
Note
在网页上找到按钮后,总是使用 click()方法选择按钮。
还有另一种单击按钮的方法,这将在本章后面讨论。可以通过以下任何方式选择默认按钮。
按 ID 选择
正如前面章节中所讨论的,ID 是一个惟一的属性,它用于方便地定位按钮元素。
#Method 1
#Finding or Identifying Default Button
default_button=driver.find_element_by_id('default_btn')
#Clicking on the button selected
default_button.click()
#Method 2
#Identifying & Clicking Default Button
default_button=driver.find_element_by_id('default_btn').click()
图 6-1 中默认按钮的 HTML 代码是定位按钮元素的来源。有两种方法。在第一种方法中,使用了两个函数,一个用于通过使用 ID 来识别默认按钮,然后通过使用click()
函数来选择默认按钮(有关更多信息,请参见第三章)。
在第二种方法中,第一种方法中的相同函数被组合在一行代码中。本章的其余部分会用到它。第一种方法可读性更强,而第二种方法比较简短。由测试人员决定使用哪一个。
Note
这两种方法具有相同的功能和目的。
ID 是在开发人员编写代码时声明的,这使得测试人员在测试用例中使用更简单。
通过文本
这是按钮最基本的选择机制。在这种选择类型中,默认按钮是通过使用写入其中的文本来选择的,该文本在浏览器中可见。
图 6-1 显示了按钮的文本及其对应的 HTML 代码。在浏览器中编译时,文本总是出现在按钮上。在 HTML 代码中,文本放在开始和结束按钮标记之间。以下 Python Selenium 代码通过文本选择按钮。
#Using text ()
button_text=driver.find_elements_by_xpath
("//button[text()='Default Button']").click()
按钮上的文本也可以使用 contain 函数和 text 函数来识别。
#Using contain () with text ()
button_text1 =driver.find_elements_by_xpath("//button[contains(text()='Default Button')]").click()
名叫
当 ID 不可用时,使用 HTML 中的 name 属性选择按钮。这就像通过名称定位 web 元素一样,如下所示。
default_button=driver.find_element_by_name('dft_btn') .click()
当有多个按钮具有相同的名称时,将选择具有该名称的第一个按钮。
接下来,让我们看看另一种类型的按钮。
提交/表单按钮
提交按钮提交插入到表单中的数据。它位于表格的末尾。表单按钮通常是通过使用<input>
标签或者将submit
作为按钮或输入标签的类型来创建的。单击此按钮时,它会导航到另一个页面,或者在动态使用时会显示一条弹出消息。图 6-2 显示了一个提交按钮及其相应的源代码。
图 6-2
提交按钮
<h1> Employee Form</h1>
<form>
Employee Name:
<input type="text" id="ename" name="ename"><br><br>
Employee Dept:
<input type="text" id="dept" name="dept"><br><br>
<input type="submit" value="Submit Button">
</form>
提交按钮只有在所有字段都被填充后才起作用,这使得它不同于默认按钮。
Note
只有当所有的表单元素都被填充时,表单按钮的 click()函数才是成功的。
按可见文本选择
选择提交按钮类似于选择默认按钮。按照相同的技术定位这些元素。下面是一个通过文本选择提交按钮的简单例子。
submit_text=driver.find_element_by_xpath
("//input[@value'Submit Button']").click()
XPath 用于通过文本定位提交按钮,文本区分大小写。
作为按钮的图像
可以使用图像创建按钮。该图像为用户提供了定制的外观和感觉。
要将图像用作按钮,输入类型必须是带有定义该图像路径的src
属性的image
。它用于两种按钮类型。下面是一个使用图像创建的按钮的简单示例。
<form>
<input type="image" id="img" name="img_btn"
src="images/go.jpg" alt="Go">
</form>
图 6-3 显示了一个用作按钮的图像。要选择一个图像按钮,可以在 Selenium 中使用下面的 Python 代码。
图 6-3
作为按钮的图像
#Image Button
image_button=driver.find_element_by_xpath("//input[contains
(@src='images/go.jpg')]")
Note
图像可以作为提交或默认类型。
为按钮断言
按钮的两个主要断言方法是验证按钮元素在网页上的存在,以及检查该元素是否被禁用。
断言方法确定按钮是否出现在给定的网页上。按钮可以出现在网页上,但也可以被禁用,这使得按钮无法被单击。click()
功能不能在禁用的按钮上操作。
检查按钮是否存在
按钮的存在让您知道按钮元素在指定的网页上是否可用。验证指定的属性或路径对于按钮是否仍然可用是非常重要的。
#Check if button is enabled or not
if default_button.is_displayed():
print("Element is Present")
else:
print("Element Not Present")
检查按钮是否已启用
当与 JavaScript 一起动态使用时,表单完成后,表单按钮被启用。只有极少数情况下禁用表单按钮;这可能是因为提交表单的日期已过,或者只能提交有限数量的表单。
#Check if button is enabled or not
if default_button.is_enabled():
print("Element is Enabled")
else:
print("Element Not Enabled")
在 Selenium 上使用 Python 中的if-else
条件来检查它的存在以及按钮是被启用还是被禁用。这些验证对于所有按钮类型都是相同的。
接下来,让我们讨论单选按钮,它是网页上提供选项的最常用按钮之一。
单选按钮
当有多个选项可用时,使用单选按钮。每个单选按钮都有相同的名称属性。当从集合中选择一个单选按钮时,其他按钮会自动取消选择。对于组中单选按钮的数量或使用单选按钮的组的数量没有限制。
以下是图 6-4 所示单选按钮的 HTML 源代码。
图 6-4
单选按钮已选中和未选中
<h3>Select your Gender:</h3>
<div>
<input type="radio" id="male" name="gender" value="male"
checked>
<label for="male">Male</label>
</div>
<div>
<input type="radio" id="female" name="gender" value="female">
<label for="female">Female</label>
</div>
<div>
<input type="radio" id="other" name="gender" value="other">
<label for="other">Prefer not to Say</label>
</div>
图 6-4 显示当一个单选按钮被选中时,其中会出现一个黑点。未选中的单选按钮中没有点。这有助于您识别单选按钮是否被选中/选中。男默认勾选,如 HTML 源代码所示。单选按钮中的选择不是强制性的。
Note
选择和选中是可以互换的。
属性值表示单选按钮的唯一值,该值仅在 HTML 代码中显示。用户无法在浏览器中看到它。该值被传输到服务器。
单选按钮有两个主要操作:选择和取消选择。接下来演示这两种操作。
选择单选按钮
有各种方法来选择需要在一组中测试的单选按钮,解释如下。
简单选择
要选择单选按钮,必须找到该元素,然后单击它。在这个方法中,使用 ID 属性选择单选按钮。
#Selecting female radio button
radio_button=driver.find_element_by_id("female")
radio_button.click()
选择的 ID 属性是 female,,它与 HTML 源代码中提供的单选按钮相关联。单击时,选定的单选按钮中会出现一个黑点。一个点可以定制成各种形状和颜色。主要目的是看到单选按钮被选中。
使用标签选择
标签是一个 HTML 标记,它写与表单 web 元素相关联的纯文本。纯文本写在标签的开始和结束标记之间。该文本也可用于选择单选按钮。
#Using label attribute with for
radio_button=driver.find_element_by_xpath("//label[@for='female']").click()
通过使用 XPath 和与之相关的属性值来选择 label 标记。点击功能在定位单选按钮后使用。
Note
单选按钮中的黑点表示该按钮已被选中。
取消选择/清除选择
单选按钮有两个相关的操作:一个是选择,另一个是取消选择。黑点仅在单选按钮被选中时可用。要清除选定的单选按钮,您需要选择另一个按钮,因为在同一个单选按钮集合中不允许多重选择。
从组中选择另一个单选按钮的方式与前面的选择类型相同。为了避免不必要的单选按钮选择,在某些情况下会引入默认选择。
Note
取消选择已经选定的单选按钮的唯一方法是从组/集合中选择另一个单选按钮。
单选按钮的断言
如果网页上有一组单选按钮,为了识别是否选中了某个按钮,或者为了确保指定的单选元素在网页上可用,就要使用断言。断言在测试单选按钮及其对应的操作中扮演着重要的角色。
断言单选按钮是否
有多种方法可以确定网页上的 web 元素是否是单选按钮。一种常见的方法是使用输入属性的属性值。如果输入类型是单选,那么 web 元素就是一个单选按钮。
#Locate Web element
radio_button=driver.find_element_by_id("female")
#If stmt to check attribute value
if radio_button.get_attribute("type") =="radio":
print("It is a Radio button")
else:
print("It is not a Radio button")
在这个例子中,使用来自get_attribute( )
函数的if
语句检查 ID 为女性的 web 元素的输入类型。
如果选中则断言
断言单选按钮是否被选中有两种方法。在第一种方法中,使用 select 函数;如果选中,则返回 true 作为布尔值,如果未选中,则返回 false。第二种方法检查单选按钮的属性值,即 HTML 源代码中的checked
。选中时,它返回 true 如果未选中,则返回 false。
#Using Selection function
driver.find_element_by_id("female").is_selected()
#Check using attribute function
driver.find_element_by_id("female").get_attribute("checked")
在某些情况下,单选按钮有默认选择。在图 6-3 中,默认单选按钮是第一个单选元素,文本为 male。可以使用返回布尔值的if
语句来检查它。
radio_button=driver.find_element_by_id("female")
if radio_button.get_attribute("checked") =="true":
print('Radio Button is "Selected')
else:
print('Checkbox is Not Selected')
断言方法检查单选按钮是否被选中。但是按钮的定位不受使用 web 定位器定位的按钮类型的影响。
接下来,让我们检查复选框。
检验盒
复选框有一个与之关联的方框。当需要用户进行多项选择时,通常会使用它们。选择复选框没有限制。您可以选择同一组/集合中的所有复选框。但是,必要时也可以限制选择。
要在 HTML 中制作复选框,输入类型是checkbox
。此属性类型让您知道断言期间复选框的存在。
<form>
<input type="checkbox" id="firefox" name="browser1" value=" b1" checked>
<label for="brower1"> Firefox</label><br>
<input type="checkbox" id="chrome" name="browser2" value="b2">
<label for="browser2"> Chrome</label><br>
<input type="checkbox" id="opera" name="browser3" value="b3">
<label for="browser3"> Opera</label><br>
<input type="checkbox" id="edge" name="browser4" value="b4">
<label for="browser4"> Edge</label><br><br>
</form>
图 6-5 显示选中和未选中的复选框。当方框中出现勾号时,您知道复选框已被选中。
图 6-5
复选框已选中和未选中
选择/检查
选择复选框就像选择单选按钮。区别在于复选框允许多选,但是单选按钮只能选一个。复选框有各种相关的属性。通过单击它来选择它。
Note
复选框可以有多个与同一组相关的选择。
使用名称检查
可以使用 HTML 源代码中的 name 属性选择复选框,如下所示。
#Select Opera check button
check_button=driver.find_element_by_name("browser3").click()
使用 ID 检查
在这个方法中,ID 属性定位 checkbox 元素,然后使用 click 函数选择它。
#Select Edge check button
check_button=driver.find_element_by_id("edge")
check_button.click()
Note
当复选框被选中时,会出现一个勾号。
断言 If 复选框
checkbox
属性类型将元素标识为复选框,如下所示。
#Identify for Checkbox
check_button=driver.find_element_by_id("chrome")
if check_button.get_attribute("type") =="checkbox":
˘ print("It is a Checkbox button")
else:
print("It is not a Checkbox button")
get attribute 函数在if
语句中用于检查复选框元素的存在。
是否选中断言复选框
选中单选按钮的方式也适用于复选框。用于在网页上识别复选框的 Python Selenium 代码如下。
#Using Selection function
driver.find_element_by_id("firefox").is_selected()
#Check using attribute function
driver.find_element_by_id("firefox").get_attribute("checked")
清除/取消选择/取消选择复选框
取消勾选选中的复选框就是取消选中,取消选中,或者清除它。这三个术语可以互换使用。在 Selenium 上的 Python 中允许清除文本框,它用于测试复选框是否正常工作。在某些情况下,该复选框被禁用或设置为默认值,不允许您清除它。
在清除复选框之前,必须先选中它。这是通过再次使用相同的click()
功能来完成的。要确定复选框是否被选中,可以使用 assert 函数。
#Clearing checkbox
check_button=driver.find_element_by_id('firefox')
#if condition to check selection
if check_button.is_selected():
#Clear using click()
check_button.click()
print('Checkbox clicked to deselected')
else:
print('Checkbox is not selected')
在这段代码中,如果复选框已经被使用if
条件语句选中,则该复选框被识别;如果选中,则清除或取消选中它。
Note
只有当复选框被选中时,才能清除它。
除了清除方法之外,复选框中使用的所有方法都是单选按钮可用的方法。选择另一个选项后,单选按钮会自动清除。复选框则不是这种情况;因此,清除/取消选择是通过执行与选择相同的操作来完成的。
接下来,让我们讨论选择列表。
选择列表
最后一个按钮类型是选择列表。当用户可以选择单选或多选时,这种按钮类型既可以作为单选按钮,也可以作为复选框。选择列表创建下拉列表中列出的多个选项。可以从列表中选择一个或多个选项。通过分别组合<select>
和<option>
标签形成选择列表。它类似于一个下拉菜单。
<h1>Blood Group</h1>
<label for="blood">Choose Blood Group:</label>
<select name = "blood" id = "bld_grp">
<option value = "A"> A type </ option>
<option value = "B"> B type </ option>
<option value = "O"> O type </ option>
<option value = "AB"> AB type </ option>
<option value = "Bombay"> Bombay type </ option>
</select>
选择列表通常在表单标记中使用,但也可以单独使用。可以控制从列表中选择的选项数量。当从列表中只能选择一个选项时,它就像一个单选按钮。当可以从列表中选择多个选项时,它就像一个复选框。
图 6-6 和 6-7 显示了一个下拉菜单,其中列出了五种人类血型。单击下拉菜单可以打开它,这也允许您从中进行选择。
图 6-7
打开选择列表
图 6-6
单项选择列表
获得所有选项
您需要知道列表中所有可用的选项。这是通过使用下面的代码完成的。
s = driver.find_elements_by_tag_name("option")
for option in s:
print("Option is: %s" % option.get_attribute("value"))
如代码所述,for
循环返回血型选择列表中的所有选项。
挑选
Selenium 中的 Python 提供了许多可供选择的方法。在从网页/app 中选择选择列表之前,你需要在 Python 中从selenium.webdriver.support.select
中导入选择库。接下来讨论选择方法。
使用可见文本选择
下拉列表中可见的文本可用作选择选项的媒介。
#Importing Select Library
from selenium.webdriver.support.select import Select
# First Select ID of drop-down
select_list=Select(driver.find_element_by_id('bld_grp'))
# select by visible text
select_list.select_by_visible_text('O type')
在下拉/选择列表的选择过程中,首先定位下拉菜单。然后,创建一个实例来从列表中选择一个选项。可以使用几个属性来定位下拉列表,例如 ID 和 name。
按值选择
与每个选项相关联的值属性是不同的。这些属性值选择选项。选择列表中的可用值为 A、B、O、AB 和 Bombay。
# Select drop-down ID
select_list=Select(driver.find_element_by_name('blood'))
# Select by visible text
select_list.select_by_value('O')
值属性区分大小写,并允许字母数字字符。
需要选择 O 型血。这是通过首先选择选项所在的下拉菜单来完成的,然后创建实例来选择指定的选项。
使用索引选择
选择列表中的选项具有 HTML 代码中未指定的索引值。Selenium 允许您使用这些索引值选择一个选项。索引值从 0 开始,与选择列表中的第一个选项相关。
# Selecting Drop-down
select_list=Select(driver.find_element_by_id('bld_grp'))
# Selecting last option Bombay by index value
select_list.select_by_index('4')
索引值 4 选择下拉列表中的最后一个选项。要使用索引值选择选项,您需要知道下拉列表中可用选项的数量。
要选择下拉列表中的最后一个选项,请使用–1 索引值,这是 Python 中常用的。
# Selecting last option Bombay by index value
select_list.select_by_index('-1')
Note
如果列表不是使用 select 标记构建的,则不能使用 Selenium 上 Python 中的 select 方法。
取消选择/清除/取消选择
从列表中选择的选项可以通过清除它来恢复。取消选择/取消选择/清除(这两个术语是同义的)选择列表中的选项可以用与选择列表中的选项相同的方式来完成。该列表可以允许单项或多项选择。
取消选择/清除一个选定的
可以取消选择列表中的单个或多个选项。下面讨论取消选择/清除单个选项。
按可见文本取消选择
列表中可见的文本可以被接受为一个值,以便在选中时取消选中它。
#clear using index
clear= Select(driver.find_element_by_id('bld_grp'))
clear.deselect_by_index('Bombay')
使用可视文本功能取消选择最后一个选项 Bombay ,。
按值取消选择
当指定的值与列表中的值属性匹配时,将取消选择该列表元素。
#clear by value
clear= Select(driver.find_element_by_id('bld_grp'))
clear.deselect_by_value ('O')
在这种情况下,可能会引发两种异常,一种是当定义的值不匹配时。第二个异常是在值匹配但没有选择列表元素时引发的,因为只有选择了列表,取消选择才起作用。
按索引取消选择
使用索引值取消选择列表中的选项。类似于选择具有索引值的选项,也可以清除/取消选择选项。
#clear by index
clear= Select(driver.find_element_by_id('bld_grp'))
clear.deselect_by_index('4')
如果选中,列表中的最后一个元素将被清除;否则,将引发异常。
多重选择列表
选择列表可以允许选择多个选项。HTML 源文件及其相应的输出如图 6-8 所示。在多项选择中,有七个选项可用,其中四个已被选中。选择这些选项的代码如下。不能使用 all_options,因为它选择所有可用列表。
图 6-8
多重选择列表
<h1>Fruit Salad</h1>
<label for="fruits">Choose Multiple Fruits:</label>
<select id="fruits" name="fruits" size="7" multiple>
<option value="apple">Apple</option>
<option value="banana">Banana</option>
<option value="cranberry">Cranberry</option>
<option value="dragonfruit">Dragon Fruit</option>
<option value="elderberry">Elderberry</option>
<option value="figs">Figs Fruit</option>
<option value="grapes"> Grapes</option>
</select>
<br><br>
<p>For Windows, hold the Ctrl button while selecting options. For Mac, hold the Command button while selecting options.</p>
在多项选择中,有七个选项可用,其中四个已被选中。代码中的选择如下。
ticks = Select(driver.find_element_by_id('fruits'))
#Selecting Options in different ways
ticks.select_by_index(0)
ticks.select_by_value ('cranberry')
ticks.select_by_visible_text('Elderberry')
ticks.select_by_index(6)
核实
断言函数用于避免在找不到元素时出现异常,或者当元素未被选择时需要取消选择该元素,反之亦然。使用选项函数可以避免这种异常,选项函数可以让您知道列表的类型以及它是否被选中。
选择第一个选项
返回多选列表中选定的第一个选项或单选列表中当前选定的选项。
selected_list=Select(driver.find_element_by_id('bld_grp'))
#Prints first selected option value
print (selected_list.first_selected_option.get_attribute('value'))
print 语句打印列表中第一个选定的选项,如果没有选择任何选项,则返回一个错误。
选择所有选项
为了从列表中获得所有选中的选项,使用了一个名为all_selected_options()
的函数。
selected_list=Select(driver.find_element_by_id('bld_grp'))
#Returns all selected options
selected_list.all_selected_options()
它主要用于返回所有选定选项的多选列表中。
取消选择/清除所有选定的
此功能从下拉列表中清除/取消选择所有选定的选项。它主要用于列表中的多重选择。当没有多项选择可用时,将引发 NotImplementError 异常。
#Clear all selected
clear= Select(driver.find_element_by_id('bld_grp'))
clear.deselect_all()
为了清除列表中所有选中的选项,Selenium 提供了deselect_all()
函数。
Note
如果列表不是使用 select 标记构建的,则不能使用 Selenium 上 Python 中的 select 方法。
摘要
本章解释了在第 3 和 4 章中讨论的鼠标/键盘动作和网络定位器,它们是用户界面上最常用的(即网络应用中的按钮)。web 定位器找到所有可用的按钮类型,并对它们执行相应的操作。
当找到默认按钮时,它只允许执行单击操作。提交按钮用于表单。单选按钮提供多个选项,但只允许其中一个选项。复选框允许多重选择。选择列表是一个按钮,根据其中的单项或多项选择进一步分为两种类型。每个按钮都有一个示例。
定位 UI web 元素,如框架和文本框,将在下一章讨论。
七、框架和文本框
前一章解释了如何定位默认、单选、复选框和选择列表等按钮。每个按钮都有与之关联的功能,如提交、选择或取消选择。按钮功能通过鼠标点击来实现(参见第三章)。本章讨论如何定位框架和文本框等 web 元素。它还解释了如何处理网页上的单个和多个框架。
本章还介绍了文本框类型、相关的 Selenium WebDriver 命令以及值插入。
内联框架
iframe 是 HTML 中另一种可用的 web 元素。它广泛用于嵌入与媒体相关的 web 元素(视频、图像等)。)在网页上。YouTube 视频和广告是网页嵌入视频和图像的两个最流行的例子。
框架可以嵌入任何 HTML web 元素。框架可以相互嵌套。Iframes 在开始时使用<iframe>
标记,在结束时使用</iframe>
标记。
Note
Iframes 的测试很重要,因为它们通常包含从其他网站或来源嵌入的 web 元素。
为了测试 iframe 中的 web 元素,您需要切换到那个特定的框架。很难定位 iframe,因为它是类似 DOM 的结构。当堆栈结构中有多个 iframe 元素时,切换到相关的 iframe 可以访问其中的 web 元素。
Note
一个内嵌框架是另一个用来描述 iframe 的术语。
在以前的 HTML 版本中,frameset 标签包含 frame 标签,但是 iframe 不需要这些标签。一个主要的区别是 iframe 中可以有嵌套的 iframe,这在框架中是不允许的。在 Selenium 中,框架和 iframes 被同等对待;因此,本章只测试 iframes。
HTML 中 iframe 的一个简单例子如图 7-1 所示。
图 7-1
单个 iframe
<iframe id="new_frame" name="apress" src="https://www.apress.com" height="300" width="300"></iframe>
前面的代码在 iframe 中显示了一个网站。您可以看到 iframe 包含到站点的链接。source ( src
)属性可以具有在网页之内或之外的 web 元素。高度和宽度可以是像素或百分比;这里使用了像素。
Note
HTML5 中不赞成使用 Frame 和 frameset 标记。而是使用 Iframes。
切换到 Iframe
与定位 web 元素类似,可以使用 switch 函数定位 iframes。当一个定义的 iframe 被切换时,那么只有测试可以在 iframe 中的任何 web 元素上执行。许多网页使用 iframe,因为在与 iframe 交互后不需要重新加载或刷新页面。以下部分描述了使用 Selenium 在 Python 中切换到 iframe 的方法。
使用 ID 切换
可以使用 ID 属性来定位 iframe,这是使用 switch 函数来完成的。Selenium 中的 Python 应用于前面的代码。ID 属性的值是new_frame
。
# Switch to the frame with id attribute
driver.switch_to_frame("new_frame")
使用名称切换
name 属性也可以用来定位网页上的 iframe。
# Switch to frame with name attribute
driver.switch_to_frame("apress")
使用索引切换
如果网页包含一个以上的 iframe(见图 7-2 ),使用索引值切换到已定义的 iframe。这个指数值是由 Selenium 提供的。以下是多个框架的 HTML 代码。
图 7-2
多重 iframe
<center>
<div><h5>Frame0</h5>
<iframe id="new_frame0" name="apress" src="https://www.apress.com" height="150" width="400"></iframe>
</div>
<div><h5>Frame1</h5>
<iframe id="new_frame1" name="bing" src="https://www.bing.com" height="150" width="400"></iframe>
</div>
<div><h5>Frame2</h5>
<iframe id="new_frame2" name="wiki" src="https://www.wikipedia.org" height="150" width="400"></iframe>
</div>
下面是 Python 代码。
# Switch to frame 1
driver.switch_to_frame(0)
# Switch to frame 2
driver.switch_to_frame(1)
# Switch to frame 3
driver.switch_to_frame(2)
不建议使用此方法,因为在网页中添加或删除其他框架时,框架的位置可能会发生变化。
Note
Selenium 从 0(零)开始初始化网页上 iframe 的索引值。
作为一个元素切换
当网页上的多个 iframe 具有相同的 id 和名称时,切换到特定的框架是很困难的。在这些情况下,iframes 可以通过 web 元素来标识。ID 和 name 等 Web 元素用于切换到已定义的 iframes。
XPath、CSS 选择器或 classname 等 Web 元素定位器用于定位 iframes。其他 web 定位器,如 linkText 或 partialLinkText,不能用于定位 iframes。当一个网页上有多个 iframess 时,标签名 web locator 不是优选的,因为很难选择一个唯一的 iframe。
# Switch to Iframes as Web Elements (Xpath)
# Switch to frame 1
driver.switch_to_frame("//iframe[@src='https://www.apress.com']")
# Switch to frame 2
driver.switch_to_frame("//iframe[@src='https://www.bing.com']")
# Switch to frame 3
driver.switch_to_frame("//iframe[@src='https://www.wikipedia.org']")
使用 XPath 定位 iframe,这对于每个框架都是不同的。
Note
由于锚标记不可用,链接或部分链接文本不用于切换 iframe。
切换到主 Iframe
有两种方法可以切换到主框架,这将在下面讨论。
默认内容
对于默认内容,所有可用的 iframes 都被终止,并且控件被切换回网页。当控件返回到页面时,不会与 iframe 中的 web 元素进行交互。
driver.switch_to.default_content()
父框架
对于父框架,当前的 iframe 被终止,并且控制被切换到它的父 iframe。如果没有对应于所选或当前 iframe 的父 iframe,则当前 iframe 被终止,并且控制被切换回网页。
driver.switch_to.parent_frame()
有等待的帧
当处理 iframes 时,您可以使用等待来切换到任何帧,因为这些帧由于外部源或链接而需要更多的时间来加载。下面是几个等待的例子。
-
Frame ID :
-
Frame Name :
iframe=WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it(By.ID,"iframe_id"))
Frame XPath :
iframe2 =WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it(By.NAME,"iframe_name"))
Frame CSS :
iframe3 =WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it(By.XPATH,"iframe_xpath"))
iframe4 =WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it(By.CSS_SELECTOR,"iframe_css_selectors"))
现在让我们继续讨论文本框。
文本框
文本框接受文本形式的用户输入。该文本存储在数据库中或由网页使用。有两种类型的文本框:单行和多行。
单行文本框
单行文本框通常被视为登录选项,其中登录名和密码都需要单行文本。文本框是单行的矩形形状;它有各种尺寸。HTML 中的输入标签定义了一个单行的文本框。下面是一个单行文本框的 HTML 示例。如图 7-3 所示。
图 7-3
单行文本框
<h1>Single Line Textbox</h1>
<label for="book">Book Name:</label>
<input type="text" id="book1" name="book">
单行文本框通常用在表单中或用作网页上的搜索框。谷歌搜索引擎是最常用的单行文本框。
多行文本框
当文本使用多行时,就需要多行文本框。多行文本框通常用于电子商务网站上的评论框或脸书上的帖子。大小可以根据行和列(高度和宽度)而变化。为了定义一个多行文本框,使用了<textarea>
标签。图 7-4 显示文本区域和其中的文本值。下面是它的 HTML 代码。
图 7-4
多行文本框
<h1>Textarea</h1>
<label for="book">Book Name:</label><br>
<textarea id="book2" cols="50" rows="5">
Python Selenium Sujay.
</textarea>
可以拖动右下角的文本区域来增加其大小。可以通过指定相应的参数来限制 textarea 的大小。
Note
不可编辑的文本框仅用于显示与其关联的值。
插入值
textbox 和 textarea 用于从用户处获取值。这些值存储在数据库中,或者对照数据库中的值进行验证,以相应地授权或应用限制。要测试 textbox 或 textarea 是否可以接收输入,您需要向它发送值。这是通过在带有 Selenium 的 Python 中使用send_keys
函数来完成的。
#Import libraries
from selenium import webdriver
#Open Firefox browser
driver=webdriver.Firefox()
#Navigate to URL
driver.get("http://www.apress.com")
#Find Search box (Single Line Textbox)
text_box=driver.find_element_by_name("query")
#String Value to be Inserted i.e. query in search box
text_box.send_keys("Python Testing with Selenium")
#Insert Value
text_box.submit()
# Quit Firefox
driver.quit()
Note
在 textbox 和 textarea 中插入值在很大程度上是相同的;唯一的区别是包含它们的行。
从 Textbox 和 Textarea 获取值
一个测试用例可以检索文本框或文本区域的输入值。在出现错误的情况下,检索与这些框相关的任何值,以便与预期值进行比较。以下是 textbox 和 textarea 的 Python 代码。
#For Textbox
text_box=driver.find_element_by_id('book1').get_property('value')
print(text_box)
#ForTextarea
text_area=driver.find_element_by_id('book2').get_property('value')
print(text_area)
摘要
本章简要介绍了 iframe 和 iframe 的定位方法。存在多个 iframes 出现在一个网页上的情况。通过一个例子解释了切换到特定 iframe 的过程。
文本框大致分为两种类型——单行和多行。多行文本框也称为 textarea。您学习了使用定位器识别这两种类型的文本框。您还了解了在两种文本框类型中插入值以及检索与指定文本框相关联的值。
下一章是关于验证 web 元素的。
八、断言
在前面的章节中,您学习了定位 web 元素,如链接、按钮、框架和文本框,以及与它们相关的测试用例。在自动化 web 应用或页面的任何测试用例之前,您需要验证它,这是通过提供关于 web 元素的条件来完成的。这种验证或检查是通过使用断言函数来完成的,这些函数在 Selenium 和 Python 中都有提供。
断言允许您使用 web 元素的分配值来验证或检查预期值。分配的值可能是与之相关的任何属性,而期望值是我们在测试中比较的值。本章解释了 Python 在 Selenium 中提供的断言及其类型和自动化任何测试用例的用法。这些断言也是 unittest 框架的一部分,这将在本书后面的章节中讨论。在这一章中,我们研究了几个由 Selenium 在 Python 中提供的断言方法,这使得编写测试用例时调试更加容易。
断言的需要
断言是一种主要用于检查或验证与 web 元素相关的特定条件或测试用例的方法。断言函数或方法给出两个结果:通过或失败(即布尔术语中的真或假)。
只有当测试条件中的两个参数或值相同,并且在运行时没有引发异常时,测试用例才会通过。类似地,当两个值不相同时,测试用例失败,并引发 AssertionError 异常(仅当使用 assert 函数时)。
断言主要用于测试测试用例中的单个 web 元素,也称为单元测试。它对相关测试用例的结果进行报告。该报告通知开发人员与测试用例相关的任何错误或缺陷。
其余部分按用法组织断言类型。每种类型都有一个简短的定义,包括语法和示例代码。
基本资产
在 Selenium 中,Python 提供了一些基本的断言,用于评估其中定义的两个值。测试用例是成功还是失败,取决于函数的结果。当测试用例失败时,会引发异常。还可以提供可选的文本消息。
assertTrue
assertTrue
测试给定的条件或结果是否为真。当条件为真时,测试用例通过,当条件为假时,测试用例失败。它验证单个值,后跟一条文本消息,这是可选的。下面是它的语法示例。
assertTrue(value1, text_msg=null)
import unittest
from selenium import webdriver
class test_case1(unittest.TestCase):
def test1(self):
s1 ="Python"
s2 ="Ruby"
# Verifying Numbers
self.assertTrue(s1== s2, "It's not a Match.")
if __name__ =="__main__":
unittest.main()
assertFalse
当指定的条件为假时,assertFalse
方法通过测试。当条件为真时,测试失败,并引发异常。它使用单个值。下面是它的语法示例。
assertFalse(value1, text_msg=null)
def test2(self):
s1 ="Python"
# Verifying Numbers
self.assertFalse(s1 == 'Ruby', "It’s a Match.")
分类
assertIs
函数将 value1 与 value2 进行匹配,看它们是否相同。当两个值相同时,测试用例通过;否则,将引发异常。下面是它的语法示例。
assertIs(value1, value2, text_msg = null)
def test_lang(self):
lang="Python"
#Check lang
self.assertIs("Selenium", lang, "value do not Match.")
资产广告
assertIsNot
验证值 1 和值 2 是否相同。如果它们不相同,那么测试用例通过;如果它们相同,测试用例失败。下面是它的语法示例。
assertIsNot(value1, value2, text_msg = null)
def test_lang(self):
lang="Python"
#Check lang
self.assertIsNot("Python", lang, "Value is Match.")
阿瑟酮
assertIsNone
检查给定的条件或值是否为空。如果为空,则测试用例通过;如果它不为空,那么该函数将引发一个异常。下面是它的语法示例。
assertIsNone(value, text_msg = null)
这里,值可以是表达式、条件或参数。
def test(self):
color=None
# Check if value is null.
self.assertIsNone(color, "color is not null")
资产声明无
如果指定的条件或值不为空,则assertIsNotNone
方法通过测试用例;否则,测试用例失败。下面是它的语法示例。
assertIsNotNone(value, text_msg = null)
def test(self):
color="green"
# Check if value is not null.
self.assertIsNotNone(color, "color is null")
资产实例
检查一个给定值是否是一个类的实例。如果对象不是实例,则会发生异常。下面是它的语法示例。
assertIsInstance(value, cls, text_msg = null)
assertNotIsInstance
当给定值是类的实例时,引发异常。如果值不是类的实例,那么相应的测试用例通过。下面是它的语法示例。
assertNotIsInstance(value, cls, text_msg = null)
比较断言
断言函数可以相互比较。使用以下断言比较两个值是大还是小。
assertequals
assertEqual
方法比较两个值。如果两个值相等,那么测试用例通过,如果不相等,那么测试用例不能引发异常。通过和失败是根据函数返回的布尔值来确定的。下面是它的语法示例。
assertEqual(value1, value2, text_msg=null)
语法定义了两个用于比较的值,如果两个值不匹配,可能会显示一条文本消息。文本消息可以为空,因此可以选择使用。下面是一个测试页面标题值的简单示例(可执行路径与前面章节中描述的相同)。
import unittest
from selenium import webdriver
class test_case1(unittest.TestCase):
def test1(self):
driver=webdriver.Firefox()
driver.get("https://apress.com")
title1 =driver.title
title2 ="Apress Home"
# Verifying Page Title
self.assertEqual(title1, title2, "Title Page do not Match.")
if __name__ =="__main__":
unittest.main()
assertNotEqual
assertNotEqual
与assertEqual
功能相反。当两个值不相等时,测试用例通过;否则,测试用例失败。下面是它的语法示例。
assertNotEqual(value1, value2, text_msg=null)
def test2(self):
num1 =7
num2 =5
# Verifying Numbers
self.assertNotEqual(num1, num2, "Numbers Match.")
资产更大
assertGreater
检查第一个值是否大于第二个值;如果是,那么测试通过,否则测试用例失败。下面是它的语法示例。
assertGreater (value1, value2, txt_msg = null)
assertgreatereequal
assertGreaterEqual
函数检查值 1 是否大于或等于值 2;如果是,那么测试用例通过。下面是它的语法示例。
assertGreaterEqual (value1, value2, txt_msg = null)
无资产
使用assertLess
,当值 1 小于值 2 时,测试用例通过,当值 1 小于值 2 时,测试用例失败。文本消息是可选的。assertLess
的行为与assertGreater
功能相反。下面是它的语法示例。
assertLess (value1, value2, txt_msg = null)
assertlesseequal
只有当 value1 小于或等于 value2 时,assertLessEqual
方法才通过测试用例;否则,测试会导致失败,并引发异常。下面是它的语法示例。
assertLessEqual (value1, value2, txt_msg = null)
def test_cmp(self):
num1 =7
num2 =5
#Check num1 is greater
self.assertGreater(num1, num2, "num1 is less.")
#Check num1 is greater than or equal to
self.assertGreaterEqual(num1, num2, "num1 is less.")
#Check num1 is less
self.assertLess(num1, num2, "num1 is greater.")
#Check num1 is less than or equal to
self.assertLessEqual(num1, num2, "num1 is greater.")
集合断言
集合是特殊类型的数据存储,其中可以存储多个元素。该集合包括用 Python 语言构建的列表、元组、集合、字典等等。
列表
assertListEqual
函数允许我们比较两个列表。当两个列表包含相同的元素时,测试用例通过;如果列表没有相同的元素,那么测试用例失败。下面是它的语法示例。
assertListEqual(list1, list2, text_msg=null)
def test_list(self):
list1 = ["python", "selenium", "apress"]
list2 = ["python", "selenium", "apress"]
#Check elements in both lists
self.assertListEqual(list1, list2, "Lists don't Match.")
元组
元素的比较在两个元组之间进行。当这两个元组中有相同的元素时,那么函数返回一个布尔值 True,这意味着测试用例通过,反之亦然。下面是它的语法示例。
assertTupleEqual(tuple1, tuple2, text_msg=null)
def test_tuple(self):
tuple1 = ("python", "selenium", "apress")
tuple2 = ("python", "selenium", "apress")
#Check elements between two tuples
self.assertTupleEqual(tuple1, tuple2, "Tuples don't Match.")
设置
与前面的函数类似,assertSetEqual
函数比较两个集合之间的元素。如果两个集合包含相同的元素,那么测试用例通过,反之亦然。下面是它的语法示例。
assertSetEqual(set1, set2, text_msg=null)
def test_set(self):
set1 = {"python", "selenium", "apress"}
set2 = {"java", "selenium", "apress"}
#Check elements from two sets
self.assertSetEqual(set1, set2, "Sets don't Match.")
词典
在assertDictEqual
方法中,一个字典中的所有可用元素都与另一个字典匹配。如果所有元素都相同,那么测试用例是成功的;如果元素不相同,那么测试用例就是失败的。文本消息是可选的。下面是它的语法示例。
assertDictEqual(dict1, dict2, text_msg=null)
def test_dict(self):
dict1 = {"lang":"python", "tool":"selenium", "publication":"apress", "year":"2020"}
dict2 = {"lang":"kotlin", "tool":"selenium", "publication":"apress", "year":"2020"}
#Check elements from two sets
self.assertDictEqual(dict1, dict2, "Dictionaries don't Match.")
主张
assertIn
检查值 1 在值 2 中是否可用。如果该值可用,那么测试用例将无任何异常地通过。下面是它的语法示例。
assertIn(value1, value2, text_msg = null)
Note
集合断言用于检查集合中 web 元素的可用性。
资产净值
像assertIn
函数一样,assertNotIn
检查 value2 中是否存在 value1。如果存在,那么测试用例失败;如果它不存在,那么测试用例是成功的。下面是它的语法示例。
assertNotIn(value1, value2, text_msg = null)
下面的程序使用assertIn()
和assertNotIn()
函数检查任何给定收集数据中元素的可用性。
def test_item(self):
collection=set(["Python", "Selenium", "Apress"])
#Check for Python element in a set
self.assertIn("Python", collection, "Element is not available in the set.")
#Check for Java element in a set
self.assertNotIn("Java", collection, "Element is available in the set.")
Note
有些断言函数没有包含在内,因为它们在 Python 的新版本中已被弃用。
这就完成了所有可以在 Python 中用于使用 Selenium 创建的测试用例的断言函数。
摘要
您学习了测试用例中的断言。您还了解了不同的断言技术,比如基本断言、比较断言和带有多个函数的集合断言。
本章中解释的断言评估或验证 web 应用中的 web 元素。断言允许您对测试用例中出现的调试问题做出报告,以便开发人员可以快速解决它们。
下一章讨论 Selenium 中的各种异常以及处理它们的方法。
九、异常
最后一章讨论了断言,它评估测试用例中的特定条件。这一章主要关注在 Python 和 Selenium 中发生的异常。首先,您需要知道什么是 Selenium 异常以及它们的各种类型。在 Selenium 测试用例中,有几个方面会引发异常。每个异常都是由特定的原因引起的,本章对此进行了解释。Selenium 提供了许多内置的异常,这些异常会导致测试用例的终止。为了避免这些不寻常的终止,应该处理一个异常,以便测试用例遵循正常(默认)的执行流程。在这一章中,我们将研究不同类型的异常,引发这些异常的原因,以及如何在 Selenium 测试用例中处理异常。让我们从定义异常和测试用例中需要异常开始。
什么是异常?
当程序的执行被异常事件中断时,就会发生异常。当一个异常被引发或者发生时,测试用例停止它的正常流程并被终止。
为什么要使用异常?
以下是在 Selenium 中使用异常的一些原因。
-
它将默认测试用例代码与错误处理代码分开。
-
没有必要在测试用例的每一点检查错误。
-
异常允许您通过任何处理错误来完成测试用例的默认执行。
-
它使得测试用例中的错误报告更加容易。
-
使用异常时,很容易对错误进行分类。
Selenium 的异常
既然您已经考虑了测试用例中出现异常的原因,那么让我们看看在执行测试用例时 Selenium 中可能出现的所有异常。每个异常都用触发异常的事件来定义。
ConnectionClosedException
当 web 驱动程序断开连接时,Selenium 会引发这个异常。
ElementClickInterceptedException
当单击元素的命令因需要单击的请求元素被隐藏或隐藏而未正确执行时,会发生此异常。
ElementNotInteractableException
在这种异常类型中,已定义的 web 元素不能与另一个元素交互或指向另一个元素,即使它存在于文档对象模型(DOM)中。
ElementNotSelectableException
无法选择 web 元素,即使它存在于 DOM 中。这引发了一个异常。这个动作属于 Selenium 中的 select。异常更可能发生在要选择的按钮中,如单选按钮、复选框等。
ElementNotVisibleException
当某个元素出现在网页上,但对要在其上执行的操作不可见时,会引发此异常。元素的不可见性是由于 HTML 标签中的隐藏类型,或者某些操作需要首先执行。这个异常通过使用 wait 来解决,wait 等待一个元素变得可见。
ErrorInResponseException
当服务器端出现错误时,会发生此异常。这在与远程服务器或 Firefox 扩展通信时很常见。下面列出了其中的一些错误。
-
400-badrequest
-
401–未经授权
-
403–禁止
-
405–方法不允许
-
409–冲突
-
500–内部服务器错误
ErrorHandler(错误处理程序)。未知服务器异常
当服务器给出一个没有堆栈跟踪的错误时,这个异常被用作占位符。
ImeActivationFailedException
当 IME 引擎无法激活时,会引发此异常。IME 是输入法引擎的缩写。它通常与被 Selenium 作为输入的中文、日文或多字节字符一起使用。IBus 是支持像 anthy 这样的日本引擎的输入框架的一个例子。
ImeNotAvailableException
当设备上不支持 IME 时,会出现此异常。
insecurexertificateexception
TLS(传输层安全性)证书如果过期或无效,会在用户端引发此异常。
InvalidArgumentException
当传递无效或扭曲的参数时,Selenium 会引发这个异常。
InvalidCookieDomainException
当试图为其他域或 URL 而不是当前 URL 添加 cookie 时,Selenium 会调用这个异常。
invalidcoordonateexception
当用户需要在相应的 web 元素上执行动作或操作时,当定义的坐标不正确或无效时,该异常被激活。当移动 web 元素或用提供的坐标单击按钮的鼠标操作失败时,会引发此异常。
InvalidElementStateException
当 web 元素被禁用或无法执行指定给它的操作时,Selenium 会引发这个异常。例如,当所有相应的字段都已填充时,提交按钮才起作用,如果您试图事先单击提交,则会引发此异常。
InvalidSelectorException
当用户没有从网页返回指定的 web 元素时,将引发 InvalidSelectorException。它更有可能是由 XPath 引发的,因为路径无效或被更改,这意味着定位 web 元素失败。
InvalidSessionIdException
如果测试用例中的会话 ID 不活动、已经过期或者不存在,那么 Selenium 会引发这个异常。
InvalidSwitchToTargetException
当需要放置或切换到目标位置的网页上没有框架或窗口元素时,会发生此异常。
JavascriptException 异常
如果 JavaScript 文件或代码片段的执行有问题,就会调用这个异常。
jsoneexception
当在未创建会话的情况下获得会话功能时,会发生此异常。
MoveTargetOutOfBoundsException
当目标 web 元素或鼠标移动无法指向定义的边界时(即,超出网页的边界,或者它是无效的),此异常由 ActionChains()保留。
NoAlertPresentException
当弹出警告(例如,警告框、提示框、确认框等)时,会发生这种异常。)目前不可用。JavaScript 引导警告弹出窗口。引发此异常的其他原因包括警告框需要更多时间来加载或在当前阶段不可用,JavaScript 在浏览器端被阻止,或弹出窗口已经关闭。
NoSuchAttributeException
如果 web 元素无法返回其属性,则会引发此异常。这是测试用例中最罕见的 Selenium 异常之一。您可以通过了解 web 元素是否有关联的属性来避免这种异常。
也可以通过更新 DOM 中可能已经改变的属性值来处理该异常。
NoSuchCookieException
当浏览器当前上下文的活动文档中存在的 cookie 中定义的 cookie 没有匹配项时,将引发此异常。
NoSuchElementException
这是 Selenium WebDriver 测试用例中最常见的异常。当 web 定位器无法从网页中跟踪或定位已定义的 web 元素时,此异常被撤销。找不到 web 元素,因为 DOM 不包含它,或者它无效。
当定义的 web 元素在 web 页面上不可用时,Selenium 抛出 NoSuchElementFoundException。以下任何原因都可能导致此异常。
-
web 元素定位器值不正确或不匹配。
-
加载页面需要很长时间,所以 web 元素没有定位。
-
在测试执行时,web 元素在网页上不可用或不可见。
NoSuchElementException 是通过从八个可用的定位器中选择一个特定的 web 定位器来处理的(更多信息见第四章)。它还指定等待以确保 web 元素已经完全加载。
NoSuchFrameException
当您希望切换到当前不可用的框架时,会发生此异常。当刷新页面时切换框架的具体细节发生变化,或者信息与任何可用的框架都不匹配,或者 web 元素不是框架,或者加载时间不足时,就会发生这种情况。
nosuchwindowsexception
当应该在浏览器窗口中执行某些操作时(如切换到已定义的窗口或移动窗口的位置),如果窗口当前不存在,则会引发此异常。当窗口尚未加载并且试图对其进行操作时,也会发生这种情况。
NoSuchContextException
在移动测试中,ContextAware 引发了这个异常。
屏幕截图异常
当 Selenium 无法对网页进行截屏时,就会出现这个异常。该异常在引发时会将屏幕截图变成黑色图像。
staleelemontreferenceexception
当 web 元素由于被删除或处于稳定状态而不再存在于 DOM 中时,会发生此异常。这很常见,因为现在大多数 web 元素都是动态的。一个简单的例子是,刷新页面可能导致已定义的 web 元素不可用。
这个异常可以由 XPath 处理,XPath 处理 web 页面上的动态 web 元素。
超时异常
当执行没有在定义的时间框架内完成时,Selenium 会返回一个超时异常。使用等待来处理异常,这使您能够为执行提供更多的时间。时间值应该是标准的,以便在测试用例的进一步执行中没有延迟。
UnableToSetCookieException
当 Selenium WebDriver 无法设置 cookie 时,会引发此异常。
UnexpectedAlertPresentException
当网页上出现意外警报时,Selenium 会发出此警报,这是由于警报(即弹出窗口)中的 Python 命令停止。
意外的标记名异常
当支持类无法定位或找到预期的 web 元素时,会发生此异常。它更常见于下拉元素中。
UnknownMethodException
当请求的 Selenium 命令与已知的 URL 匹配,但与为该 URL 指定的方法不匹配时,会引发此异常。为了避免这种异常,您需要在测试用例中声明方法之前检查它。
WebDriverException
这是一个基类 Selenium WebDriver 异常,当 WebDriver 和目标 web 浏览器不兼容时会调用它。所有其他异常都属于这个基类。
异常处理
现在您已经知道了 Selenium 测试用例中出现的所有异常,让我们来研究处理它们的正确方法。异常出现后继续执行测试用例的过程称为异常处理或处理异常。处理异常是为了执行和避免测试用例不必要的终止。
异常会妨碍下一个需要执行的有效语句,因此,Selenium 提供了一个处理异常的解决方案。可以通过跳过或忽略引发的异常来处理异常,因此,测试用例继续以其正常流程执行。
Note
处理异常减少了调试时间。
使用 Python 中的 try-except 方法处理异常。通过定义一个异常,当它在测试用例执行期间出现时,你可以忽略或者跳过它。异常处理有助于减少测试用例中的错误失败,并导致找到实际的 bug(如果有的话)。接下来讨论测试用例中异常处理的一些常见例子。
超时异常
web 元素定位器等待指定的时间,以便加载完整的页面。
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
driver=webdriver.Firefox(executable_path=r'C:\folder\geckodriver.exe)
driver.get("https://apress.com")
try:
# Web driver waits for 5 seconds to locate web element
WebDriverWait(driver,5).until(EC.presence_of_element_located((By.ID, "query")))
except TimeoutException:
# When loading page takes more time
print("Taking more time to load.")
找不到元素
这是 Python 和 Selenium 中最常见的异常之一。
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.action_chains import ActionChains
driver=webdriver.Firefox()
driver.get("https://apress.com")
try:
web1 =driver.find_element_by_id("privacy")
web1.click()
except NoSuchElementException as exception:
print ("Web Element is not Available in the given Web Page.")
陈旧元素
当 web 元素不再出现在 DOM 中时,就会出现陈旧元素。此异常在以下程序中引发,方法是在 web 元素首次提交一段时间后提交该元素。忽略或跳过试图终止测试用例的已处理异常。类似地,任何异常都可以被处理。同样的方法也可以用于测试用例中可能出现的多个异常。
from selenium import webdriver
from selenium.common.exceptions import StaleElementReferenceException
import time
driver= webdriver.Firefox(')
driver.get('http://apress.com')
driver.find_element_by_name('query').send_keys('python selenium')
while True:
try:
s=driver.find_element_by_class_name('search__submit')
s.submit()
time.sleep(2)
s.submit()
except StaleElementReferenceException:
print('Stale Exception is Skipped.')
break
driver.quit()
Note
Selenium 中的每个异常的处理方式与 Python 中的相同(即使用 try-except 方法)。
异常处理终止测试用例的忽略或跳过。任何异常都可以处理。同样的方法也可以用于测试用例中可能出现的多个异常。
摘要
本章介绍并定义了 Selenium 异常。您了解了在测试用例中出现 Selenium 异常的原因。
定义了几乎所有在 Selenium 测试用例中可能出现的异常,并解释了它们在测试执行期间出现的原因。在上一节中,您学习了在一个示例测试用例中处理最常见的异常。
下一章将讨论等待,在等待中,测试用例被延迟一段特定的时间。
十、等待
第九章是关于测试用例中可能出现的各种异常,你已经看到了如何处理它们。本章简要介绍了 Selenium 上 Python 中使用的等待。等待可以最小化测试用例运行期间触发的大多数异常。
有时,在执行特定操作后或经过一段时间后,web 元素才可用。这些操作是在用户端通过表单、按钮或鼠标/键盘操作完成的,这些操作将用户导航或重定向到另一个网页。
这些操作也可以使用 AJAX 来执行,AJAX 是 JavaScript 和语言的组合(因此缩写来自异步 JavaScript 和 XML)。在代码中使用 AJAX 或 JavaScript 来控制 web 元素的可用性或可见性。AJAX 或 JavaScript 的广泛使用是因为它
-
更新 web 应用/页面,无需再次加载
-
加载页面后请求服务器数据
-
加载页面后接收服务器数据
-
将数据发送到服务器,无需再次刷新/加载页面
接下来解释等待的必要性。
Note
AJAX 可以以纯文本或 JSON 文本的形式发送或接收数据。
为什么需要等待?
大多数 web 应用/页面都是通过 AJAX 或 JavaScript 使用 AngularJS、NodeJS、ReactJS 等框架制作的。这些应用通过刷新(重新加载)页面或加载页面来加载网页元素。为了定位这样的 web 元素,Selenium 提供了等待。
Python 脚本被编写来自动化用户的交互。考虑一个简单的例子:当一个表单被填写,点击提交按钮,页面被重定向。提交之后,web 元素就可用了。隐藏 web 元素是使用 JavaScript 或 AJAX 完成的。要使这些 web 元素可见,您必须等待执行特定的操作或加载页面。因为元素是隐藏的,所以无法解决引发的任何错误或异常。Selenium 等待主要用于克服重定向 web 应用时出现的这类错误。等待还通过定位 web 元素来处理异常的数量。
以下是 web 元素无法定位的众多原因中的几个。
-
由于使用 AJAX 或 JavaScript 时时间的变化,所有的 web 元素还没有完全加载到 web 页面上。
-
只有当用户执行指定的操作时,web 元素才可用。
-
对网页的响应有延迟。
-
网页/应用表现不佳,web 元素无法加载。
等待的类型
等待处理来自 Selenium WebDriver 的 ElementNotVisibleException 和 NoSuchElementException 之类的异常。等待由在网页上定位 web 元素的条件来定义。根据条件的不同,Selenium WebDriver 通常将等待分为三种类型:隐式、显式和流畅。
隐形的
在隐式等待中,WebDriver 会在调用 NoSuchElementFound 异常之前等待(轮询 DOM)一段指定的时间。默认等待时间为零秒。它可以在页面上可用的任何 web 元素上实现。
Note
DOM 代表文档对象模型,是 HTML 和 XML 的接口。
等待条件在 Python 脚本中定义,该脚本查找给定页面上指定 web 元素的存在。直到在条件脚本中设置的时间范围内找到 web 元素,WebDriver 才会继续。如果在设定的时间内没有找到元素,就会引发异常。
等待 web 元素的概念来自 Watir 工具。清单 10-1 展示了一个隐式等待的例子。(请注意路径在章节 1 和 2 中有解释。)
# Import Selenium Libraries
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
# Time frame set for 10 seconds
timeout =10
# Creating Firefox driver instance
driver = webdriver.Firefox()
# Calling Implicit wait function
driver.implicitly_wait(timeout) #driver.implicitly_wait(10) Time frame can diretly be set
# Go to URL www.apress.com
driver.get("http://apress.com")
print("It's an Implicit Wait")
# Retrieving ID element
new_element = driver.find_element_by_id("query")
# Type "Python with selenium" in search bar
new_element.send_keys("Python with selenium")
# Submit text in search bar
new_element.submit()
# Close Firefox browser
driver.quit()
Listing 10-1Implicit Wait
在本例中,web 驱动程序等待 10 秒钟,通过 ID 查找/定位 web 元素。测试人员确定时间范围。web 驱动程序尝试在定义的时间范围内搜索指定的元素;如果找到,web 驱动程序将返回该元素,提交指定的文本,并关闭浏览器。如果找不到元素,则会引发异常。
Note
隐式等待用于不立即可用的 web 元素。
明确的
满足特定条件后,页面上的 web 元素被加载或变得可用。这些条件可能因元素而异。在这种情况下,不能使用隐式等待,因为它只能等到元素被加载或出现。等待时间不能急剧增加,这可能会导致更多的时间来执行整个脚本。这导致了隐式等待的改进版本的使用,它被称为显式等待。
考虑一个动态网页,它有一个只能在用户交互后加载的元素。如果使用隐式等待,它会等待指定的时间,然后因为元素不存在或不可见而引发异常。显式等待用于定位这些元素。显式等待在使用时定义了两个条件:WebDriver 等待和 Python 类中的 ExpectedConditions。
第一个条件是 WebDriver wait,它定义了一个等待一定时间的整数值。第二个条件定义了指定 web 元素的预期条件。ExpectedConditions 是 Selenium WebDriver Python 库中可用的预定义函数/方法。当满足预期条件时,WebDriver 不会等待定义的等待完成,而是继续执行 Python 脚本中的下一条代码指令。这是隐式和显式等待的主要区别。
Note
显式等待的默认轮询频率是 500 毫秒(0.5 秒),不能更改。
# Import all Necessary Selenium Libraries
from selenium import webdriver
Missing python timeout exception
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
# Creating Firefox driver instance
driver = webdriver.Firefox()
# Go to URL www.apress.com
driver.get("https://www.apress.com")
# Time frame set for 10 seconds
timeout =10
try:
# Returns ID element, when successful
new_element = WebDriverWait(driver,timeout).until(
EC.presence_of_element_located((By.ID, "query")))
# Type "Python with selenium" in search bar
new_element.send_keys("Python with selenium")
# Submitting text in search bar
new_element.send_keys(Keys.ENTER)
except TimeoutException:
print("Failed to locate search bar")
finally:
driver.quit()
# Closing Firefox browser
driver.quit()
Listing 10-2Explicit Wait
在清单 10-2 中,时间范围被设置为 10 秒。驱动程序访问 Apress web 页面,它的 ID 属性定位一个元素。在指定时间内检查 web 元素,如果可用,则返回;否则,会遇到异常。因此,如果使用循环,可能需要无限长的时间才能满足条件。当存在页面重定向时,循环失败。当设置等待时,它定期检查,并在定位到元素或时间结束时退出流程。
Note
混合隐式和显式等待会导致无限长的等待时间。
显式等待使用定位 web 元素所需的 ExpectedConditions。接下来将描述这些情况。
Python 类中常用的预期条件
预期条件通常会自动执行测试脚本。这些条件是经常遇到的,主要用于显式等待。
ExpectedConditions 是在 Selenium 包库中用 Python 预定义的。在合并之前,您需要安装并导入 Python 脚本。预期条件在expected_condition
模块中可用。导入库文件的 Python 脚本是from selenium.webdriver.support import expected_conditions as ec
。
Note
ec 是 expected_conditions 的缩写形式,通常在 Python 语言中使用。
预期条件是针对 web 元素的。下面描述了通常用于自动化测试的预期条件。
-
警报存在
它检查在指定的时间范围内网页上是否出现警告。如果存在,它返回警报对象;否则,它会引发 Selenium 常见异常,如 TimeoutException。
-
element _ located _ selection _ state _ to _ be(ui _ locator,is _ select)
它检查 web 元素是否可以被 web 页面上的任何定位器定位,并检查其选择状态。如果在设定的时间范围内找到具有所需选择状态的指定 web 元素,则不会引发异常。
-
元素 _ 定位 _ 待选(ui_locator)
它检查 web 元素在时间范围内是否处于网页上的选中状态。可以使用第四章中提到的任何定位器来定位该元件。找不到元素时会引发异常。
-
元素 _ 选择 _ 状态 _ 目标(ui _ 元素,is _ 选择)
类似于element _ located _ selection _ state _ to _ be;唯一的区别是,在这种情况下,传递的是 web 元素,而不是标识它的定位器。它还在返回元素之前检查所标识元素的状态。
-
element _ to _ be _ clickable(ui _ locator)
在这种情况下,web 元素应该处于一种不可见的状态,允许在其上使用单击机制。这个异常条件一直等到设定的时间,并尝试使用定位器定位指定的可点击 web 元素。如果没有遇到具有点击的元素,则调用异常。
-
待选元素(ui_element)
它检查 web 元素是否处于选中状态。它类似于被定位为被选中的的元素,但是在这个方法中,通过直接传递 web 元素来代替定位器,元素处于选中状态。当在设定的时间限制内未找到元素时,将引发异常。
-
frame _ to _ be _ available _ and _ switch _ to _ it(ui _ locator)
它在设定的时间内检查网页上的指定框架并切换到该框架。如果该帧存在,则给定的驱动程序会切换到该帧,否则会引发超时异常。
-
不可见元素定位(ui 定位器)
它检查指定的元素在定义的时间内在 DOM 中是否可见/不可见。这个元素可以是定位器,也可以是 web 元素。当 web 元素不可见或从 DOM 中删除时,没有超时或没有这样的元素异常。
-
标题 _ 是(标题)
它检查指定的文本是否在网页的标题中。文本区分大小写。文本必须与网页标题完全匹配;否则,它会返回超时异常。
-
(ui _ element)的过时状态
这个方法一直等到一个元素不再与 DOM 相关联。web 元素已经变旧或者已经从 DOM 中删除,因为部分或整个页面,或者只有元素被刷新,这在 Selenium 中被称为陈旧元素。如果没有找到陈旧的元素,那么它返回一个布尔值 False。
-
text _ to _ be _ present _ in _ element(ui _ locator,inner_text)
它检查指定的文本是否存在于所识别或定位的 web 元素中。在这里,定位器找到元素,然后检查文本。如果元素中存在文本,则不会引发异常。
-
text _ to _ be _ present _ in _ element _ value(ui _ locator,value)
它检查文本是否出现在时间范围内元素的 value 属性中。如果不存在,则引发两个异常之一(即超时或 NoSuchElement)。
-
标题 _ 包含(标题 _ 文本)
它检查指定的文本是否出现在网页的标题中。如果部分或全部指定文本出现在网页标题中,则返回匹配的网页标题。文本区分大小写。
-
可见性 _of(ui_element)
它检查 DOM 页面中的 web 元素是否可见。这里,可见性意味着元素不仅具有大于 0(零)的高度和宽度,而且元素是否被显示。
该方法检查 web 元素在 DOM 页面上是否处于隐藏状态,或者是否由于超时或用户交互而对用户可见。如果元素不可见,将引发异常。
-
可见性 _ of _ 所有 _ 元素 _ 定位(ui_locator)
它检查所有的 web 元素是否都存在于 DOM 中并且可见。元素应该以大于零的高度和重量显示。它返回所有定位的可见 web 元素;否则,将引发异常。
考虑一个包含七个元素的网页;只有四个可见,其他三个处于隐藏状态。在这种情况下,web 驱动程序会在分配的时间段内等待其他三个元素可见。如果元素没有从隐藏状态切换到可见状态,则会引发超时异常。
-
visibility _ of _ any _ elements _ located(ui _ locator)
它检查是否至少有一个元素在 DOM 中注册并且在 web 页面上可见。可见性标准是相同的;例如,在一个 web 页面中,有五个 web 元素出现在 DOM 中并且可见。WebDriver 试图在三个中找到一个来满足预期的条件。如果在 DOM 中没有可见的或注册的,则会引发异常。
-
可见性 _ 元素 _ 位置(ui _ 定位器)
它分别检查由定位器跟踪的、在 DOM 中注册的以及可见的元素。显示 web 元素,并且其尺寸(即,高度和重量)大于零。
-
不可见元素定位(ui 定位器)
它检查 web 元素在 DOM 中是否存在,在 web 页面上是否可见。这是visibility _ of _ element _ located(ui _ locator)的一个对比条件。当一个元素仍然可见,并且在设定的时间限制内没有切换到隐藏状态时,就会引发异常。
-
新窗口已打开(当前句柄)
在这种情况下,会打开一个新窗口,并且窗口句柄的数量会增加。
-
目标窗口数量(窗口数量)
它检查窗口的数量是否有一定的值。该值是在给定方法中定义的整数。当该值与窗口数匹配时,不会引发异常。
-
url_changes(网址)
在这种情况下,当前的 URL(统一资源定位符)被新的 URL(即预期的 URL)改变。当网页的 URL 改变时,则使用该条件。当前和预期的 URL 不应相同。如果当前 URL 没有更改,则会引发异常。该 URL 区分大小写。
-
url_contains(网址)
检查定义的 URL 字符串以查看当前 URL 是否包含它的任何部分。如果它与子字符串匹配,则不会调用任何异常。该字符串区分大小写。
-
url_matches(url)
它用定义的 URL 字符串检查当前 URL。该条件检查当前 URL 中的确切模式。如果检测到该模式,则不调用异常。该模式可以是正则表达式。
-
url_to_be(url)
它根据预期的 URL 检查当前的 URL。它类似于 URL_matches(URL)方法,但唯一不同的是,该方法使用实际的 URL,而不是正则表达式格式。当前 URL 应该与预期的 URL 完全匹配,否则会引发异常。
-
所有元素的存在位置(定位器)
它检查网页中是否存在至少一个使用定位器识别的元素。同一个网页上可以出现多个 web 元素,它们通过定位器进行匹配。如果返回匹配的 web 元素列表,则不会引发异常。匹配元素的数量是在一个时间范围内完成的。
-
定位元素的存在(定位器)
它检查 web 元素在 web 页面 DOM 上是否可用。DOM 上元素的可用性不一定是可见的。定位器找到元素。当 DOM 中不存在某个元素时,会引发异常。
Note
在一个时间框架内设定预期条件;如果不满足条件,则调用超时异常。如果元素存在,则可以自定义时间约束。
隐性和显性的区别
既然你已经回顾了隐式和显式等待,让我们看看它们之间的区别,如表 10-1 中所提供的。
表 10-1
隐式和显式等待的区别
|隐形的
|
明确的
|
| --- | --- |
| 它可以应用于网页/应用上所有可用的 web 元素 | 仅适用于用户与之交互的元素 |
| 无法定义预期的条件 | 需要定义预期的条件 |
| 元素只能通过等待指定的时间来定位 | 在设定的时间内检查预期条件以定位元素 |
| 不能忽略指定的时间 | 当满足预期条件时,剩余时间被忽略 |
流利的
流畅等待设置 web 元素的等待时间和轮询频率。定期检查 web 元素,以在设定的时间范围内定位。轮询频率和时间范围可以根据需要变化。流畅等待尝试在指定的时间范围内定期跟踪/定位 web 元素,或者直到找到该元素。
当使用 AJAX 的 web 元素花费的时间比平时长,或者在较短的时间间隔内变得可见时,流畅的等待非常有用。它允许您忽略任何异常。这些例外是用时间间隔和轮询频率指定的。清单 10-3 给出了一个流畅等待的简单 Python 脚本。
Note
对于实时 web 应用,建议使用流畅的等待,因为轮询会获得更新的结果。
# Import all Necessary Selenium Libraries
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import ElementNotVisibleException
from selenium.common.exceptions import ElementNotSelectableException
# Creating Firefox driver instance
driver = webdriver.Firefox()
# Go to URL www.apress.com
driver.get("https://www.apress.com")
# Time frame set for 10 seconds
timeout =10
# Fluent Wait with time interval, poll frequency and exceptions
wait = WebDriverWait(driver, timeout,
poll_frequency=1,
ignored_exceptions=[ElementNotVisibleException, ElementNotSelectableException])
# Retrieving ID element
new_element = wait.until(EC.presence_of_element_located((By.ID, "query")))
# Close Firefox browser
driver.quit()
Listing 10-3Fluent Wait
时间范围为 10 秒的流畅等待和轮询频率设置为每秒检查一次 web 元素,直到超时,如程序 3 所示。如果引发类似 NoSuchElementExceptions 和 ElementNotVisibleException 的异常,也将被忽略,最后关闭浏览器。
Note
可以定制流畅等待中的轮询频率。
摘要
等待为页面刷新/加载以及 web 应用中 web 元素的不适时出现提供了真正的解决方案。本章解释了 Selenium 支持的不同类型的等待(隐式、显式和流畅)。
隐式等待提供了在 web 应用中定位指定 web 元素的时间范围。显式等待有时间框架和预期条件;任一个都被验证为满足定义的条件。还详细解释了显式等待中出现的预期条件。最后,通过实例探讨了流畅等待。fluent wait 是 wait 中的一个改进版本,因为它支持时间限制、轮询频率,并且在其功能中可以忽略一个异常。
需要一个模型来整合我们到目前为止学到的各种测试用例。这个模型是建立在页面对象上的。下一章将讨论页面对象和与之相关的模型。
十一、页面对象
在前面的所有章节中,您学习了为网页中的 web 元素编写各种测试条件。通过组合这些条件来构建测试用例。构建一个成功的测试用例需要一个模型,在这个模型中,所有基本的功能和方法都集成到一个测试用例或脚本中。当测试用例被捆绑到一个单一的脚本中时,测试脚本的复杂性增加了,这使得阅读、修改或维护变得困难。页面对象用于解决网页上混乱的测试脚本问题。
本章从讨论页面对象开始。后面的章节涵盖了自动化测试最广泛使用的模型。本章还描述了该模型在当今环境中的必要性。此外,您将学习基于页面对象构建模型的完整过程,这是一种广泛使用的测试模型。这个模型在本章的一个经典例子中进行了定义。对模型的 Selenium 支持也有助于封装测试用例。现在让我们从页面对象概述开始。
页面对象概述
页面对象是为网页初始化的类(Python 中面向对象的概念)。页面对象中定义了 web 元素,就像 Python 语言中的属性一样。page object 类充当存储 web 元素及其动作和与 web 页面/应用相关联的验证的媒介。使用页面对象可以很容易地访问 Web 元素。根据需求,可以在 Python 测试脚本中定义多个页面对象。
页面对象的基本概念是隐藏定位 web 元素的逻辑(例如,用户 ID、XPath、CSS 选择器等)。)在输入值时与网页上的这些元素进行交互,从而将逻辑字段和值字段分开。
Note
页面对象最适合具有多个页面的 web 应用。
现在让我们看一个使用页面对象构建的模型。
页面对象模型(POM)概述
在测试自动化中,出现了一种设计模式或模型,它允许更多的功能、可维护性、可读性和灵活性。这种基于页面对象的设计模型/模式被称为页面对象模型(POM)或页面对象模式。
(这些术语可以互换使用,但本书只使用 POM。)
页面对象比非结构化的 Selenium 测试脚本更好,非常适合简单的测试用例/场景。随着测试用例在多个网页中的增加,测试脚本的复杂性也增加了。为了将测试用例绑定在一起并简化测试脚本,开发了使用页面对象的设计模型或模式。
Selenium WebDriver 测试领域中的 POM 是由 Simon Steward 提出的。页面对象模型的第一个实现是在 Java 中完成的,后来被 C#、Ruby 和 Python 采用,因为它们都支持面向对象的概念。
POM 是自动化 Python 测试脚本的一种有组织的方式。它包含与用户操作或交互相关联的 web 元素,并且经过测试,这意味着 POM 为页面对象提供了封装。
最初,页面对象是为每个 web 页面定义的,但是由于 web 元素的动态特性,对象也可以被定义为 Python 测试用例中的类或函数。近年来,在 Selenium 的自动化测试中,页面对象的使用越来越多。
Note
页面对象也用于单个网页或应用中可用的重要 web 元素,尽管有术语页面对象。
对页面对象模型的需求
当每个网页或专门的 web 元素被表示为一个类时,那么 page 对象就充当 page 和 AUT 之间的接口媒介。类中描述的方法是执行时与网页用户界面交互的测试用例。
使用 POM 的一个主要原因是网页 UI 的变化不会影响测试用例。更改是通过修改与之相关的页面对象来处理的,这样可以节省编写新测试的时间和精力。
接下来解释实现该模型的过程方式。
创建页面对象
页面对象模型被分成不同的模块。这些测试模块包含一个链接到其他模块文件的主测试页面。这些模块与指定测试用例的元素、定位器和页面相关。
接下来提供了一个 POM 测试用例示例,其中 test.py 是主测试用例文件,后面是附属文件:page.py、elements.py 和 locators.py。
要执行 POM,需要在命令提示符下运行 test.py,每个附属文件在被调用时都会被逐一执行。
现在,让我们从 test.py 文件开始,创建构成 POM 所需的每个页面。
Test.py
test.py 是一个使用 POM 架构开发的测试用例。test.py 页面包含测试特定网页或应用所需的所有测试用例。在这个例子中,POM 被设计用来测试在 Apress 网站上搜索一个关键字,然后获得匹配的结果。test.py 需要导入相关的模块,称为 page.py 文件,以完成测试用例。
将所有四个文件保存在一个目录中。不要单独运行它们,因为它是页面对象模型,类似于 Java 中的页面对象模式。
import unittest
from selenium import webdriver
import page
class ApressSearch(unittest.TestCase):
#Sample test case using Page Object Model
def setUp(self):
self.driver = webdriver.Firefox(executable_path=r'')
self.driver.get("https://www.apress.com")
def test_apress_search(self):
#Visits aprèss.com
home_page = page.HomePage(self.driver)
#Searches "Python Selenium" keyword
home_page.search_text ="Python Selenium"
home_page.click_submit_button()
search_results_page = page.ResultPage(self.driver)
#Checks if page is not empty
assert search_results_page.check_search_results(), "No results found."
def tearDown(self):
self.driver.close()
if __name__ =="__main__":
unittest.main()
test.py 文件访问指定的网站(Apress.com),然后通过搜索框搜索“Python Selenium”。无论结果页面是否为空,都会用断言进行验证。
Note
test.py 文件只包含测试用例。
Page.py
page.py 文件是为应用中可用的每个网页创建的。在这个文件中,定义了关于测试用例的操作。这一页从技术方面将测试代码和它的实现分开。该页面应该导入元素和定位器文件以及标准的 Selenium 库。
from elements import BasePageElement
from locators import HomePageLocators
class SearchText(BasePageElement):
#The locator for search box where search string is entered
locator ='query'
class BasePage(object):
def__init__(self, driver):
self.driver = driver
class HomePage(BasePage):
#Actions items for Home Page
#Variable containing retrieved text
search_text = SearchText()
def click_submit_button(self):
#Search is initialized
element=self.driver.find_element(*HomePageLocators.SUBMIT_BUTTON)
element.click()
classResultPage(BasePage):
#Actions items for result page
def check_search_results(self):
# Checks the result for specified text if found or not
return "No results found." not in self.driver.page_source
提交按钮单击操作在此页面中定义。它验证搜索页面结果是否可用。
Elements.py
elements.py 包含一个为每个页面初始化的类。此页面查找与执行操作的功能相关联的必要 web 元素。它还可以设置定位 web 元素的条件。
from selenium.webdriver.support.ui import WebDriverWait
class BasePageElement(object):
#Used in every page
def__set__(self, obj, value):
#Contains specified text
driver = obj.driver
WebDriverWait(driver, 100).until(lambda driver: driver.find_element_by_name(self.locator))
driver.find_element_by_name(self.locator).clear()
driver.find_element_by_name(self.locator).send_keys(value)
def__get__(self, obj, owner):
"""Gets the text of the specified object"""
driver = obj.driver
WebDriverWait(driver, 100).until(
lambda driver: driver.find_element_by_name(self.locator))
element = driver.find_element_by_name(self.locator)
return element.get_attribute("value")
在这个页面中,web 元素在等待定义的时间后被定位,然后通过 page.py 文件提供给 test.py。
Locators.py
locators.py 页面包含需要定位的 web 元素的名称。这将页面与元素和定位符分开。定位器值的任何更改都在此页面中完成。
from selenium.webdriver.common.by import By
class HomePageLocators(object):
#Should contain all locators from main page
SUBMIT_BUTTON = (By.CLASS_NAME, 'search__submit')
class ResultPageLocators(object):
#It should contain locators from result page
pass
初始化的定位器被传递给 elements.py,它在那里定位指定页面的 web 元素。POM 有时被认为是使用 Python 部署 Selenium 测试用例的框架。一个被称为 unittest 的测试用例框架与 POM 相结合。在第十二章中有描述。
页面对象模型的优点
这一部分主要关注用页面对象创建的测试用例的优点,如下所示。
-
减少代码重复:大部分进行测试的网页所需的基本测试脚本都需要重写,这就造成了代码的重复。这种代码重复可以通过使用页面对象来避免,因为相同的测试脚本具有为各种 web 元素指定的页面对象,并且可以用于其他页面。
-
增强代码维护:页面类的创建有助于分离 web 元素(数据)和测试用例。这使您能够在不断变化的环境中避免不稳定的测试套件条件。测试用例中异常的处理意味着更易维护的测试脚本。
-
更短的测试用例:使用 POM 对测试脚本进行了优化,因此减少了测试用例的长度。
-
增加代码可重用性:使用页面对象的代码可以在多个测试用例中使用。
-
可读性:为任何 web 应用编写的测试脚本,对于一个新的测试人员或者在同一个项目中工作的多个测试团队来说,应该是可以理解的。这是通过使用 page 对象来完成的,它将 web 元素或 web 页面分成几个部分,这使得测试脚本更具可读性。
页面对象模型的局限性
现在让我们看看在测试用例中使用页面对象的局限性。
-
时间和精力:当一个网页或应用有大量页面时,使用页面对象会有很大的风险,因为即使是应用中很小的变化,测试模型也需要修改。因此,POM 应该与 web 应用/页面的开发并行使用。
-
高级技能:要调试或编写符合 POM 的测试用例,您必须具备技术知识和经验,因为复杂性随着组合页面对象架构的增加而增加。
-
固定模型:用 POM 开发的测试不能在其他应用上使用(即 POM 不是通用模型)。
摘要
本章提供了构建模型的页面对象的完整概述。页面对象是将网页分成更小的部分的类,这些部分区分了其中可用的多个 web 元素。这是创建模型的基本构件。
您了解了页面对象模型的概念和技术实现方面。POM 的创建包括一个文件结构,该文件结构包含一个主 Python 文件和驻留在单个目录中的附属 Python 文件,如示例中所示。
您还了解了 POM 的优点和局限性。
本书的最后一章包括使用不同函数编写的各种测试用例。
十二、使用测试用例和截图
Selenium 上的 Python 程序测试 web 应用或 web 页面上的指定元素,称为测试用例。Selenium with Python 是测试 web 应用或网页的流行选择,因为实现它的学习曲线较低。Python 是一种易于理解的语言。测试要求您为 web 应用生成简单、可理解的测试报告,这可以通过 Python 和 Selenium 的结合来完成。
本章讨论了用于截图的各种测试用例。在前一章中,您学习了 POM 如何创建测试用例。
现在让我们研究一下 Selenium 中 Python 支持的最广泛使用的框架。还讨论了作为网页测试用例的框架实现。首先,让我们快速回顾一下测试结果。
测试结果
测试代码有三种结果:通过、失败或错误。这些结果定义了需要在测试用例中提供的变更。下面提供了一个快速描述。
通过/合格
通过/通过是开发人员通常期望的结果。这意味着应用在功能和客户满意度方面是理想的,没有错误。这是通过严格测试网页或应用来实现的。当测试通过时,应用不需要任何更改或错误修复。
失败
当相应的 web 元素或其行为不满足测试条件时,测试失败。当测试用例失败时,系统会引发 AssertionError 异常。向开发人员说明此错误,以便进行必要的更改,这些更改也是经过测试的。
错误
引发异常时会发生错误。该错误可能是由逻辑、语法或语义引起的,可以通过引发的异常进行跟踪。此异常不是 AssertionError。
现在让我们看几个测试案例,在这些案例中,使用多种方法实现了相同的目标。
测试用例 1:截图
这个测试用例获取网页的图片(即屏幕截图)。通过指定高度和宽度来确定屏幕截图的大小。这对于 bug 分析报告、查看测试用例流程以及恢复失败的测试用例非常有用。
有三种方法可以用来在 Selenium 中捕获屏幕图像。每一个都在下面描述。
save_screenshot('文件名称')
在这种方法中,屏幕截图是在测试用例的执行过程中拍摄的。该屏幕截图的扩展名为. png。下面是它的 Python 代码。
from selenium import webdriver
new_driver=webdriver.Firefox()
new_driver.get('https://apress.com')
new_driver.save_screenshot('screenshot1.png')
get _ snapshot _ as _ file('文件名称')
这种方法直接将截图保存为图像。png 格式。除了以外的任何其他图像扩展。png 抛出一个错误。下面是它的 Python 代码。
#get_screenshot_as_file()
from selenium import webdriver
driver=webdriver.Firefox()
driver.get('https://apress.com')
driver.get_screenshot_as_file('screenshot2.png')
#Error Occurs when image extension is changed
#driver.get_screenshot_as_file('screenshot2.jpg')
get_screenshot_as_png()
在此方法类型中,屏幕截图以二进制形式捕获,然后转换为图像。保存的图像存储在中。png 格式。下面是它的 Python 代码。
#Get method
from selenium import webdriver
from PIL import Image
from io import BytesIO
driver= webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
driver.get('http://apress.com/')
#Logo Image extraction
element=driver.find_element_by_class_name('brand')
location=element.location
#saves logo image as screenshot
size=element.size
png=driver.get_screenshot_as_png()
driver.quit()
#PIL library is used to open image in memory
image=Image.open(BytesIO(png))
#Logo size extraction
left= location['x']
top= location['y']
right= location['x'] + size['width']
bottom= location['y'] + size['height']
#Saving Logo for extracted dimension size
image=image.crop((left, top, right, bottom))
image.save('C:\\Users\\ADMIN\Desktop\\python books\\#Go Lang\\Done\\final\Apress\python testing\\codes\\screenshot3.png')
Python 图像库(PIL)用于转换二进制图像。它有 Python 版本。在实现这个函数之前,指定图像的大小。
Note
在 Selenium 上的 Python 中,save_screenshot()和 get_screenshot_as_file()方法只能将图像存储在。png 格式,而 get_screenshot_as_png()方法可以存储多种格式的图像。
现在我们来看看测试框架和 Selenium 实现中使用的最流行的测试框架。
测试框架
一个测试用例由一套规则和规章管理,这是由一个框架来完成的。该框架用于测试,因此被称为测试框架。测试框架使得测试用例更加有效和健壮。该框架包括处理测试数据、测试标准、测试存储库、页面对象等特性。
几个 Python 框架可以和 Selenium 一起使用。最常用的框架之一是 unittest。接下来描述 unittest 框架,包括它的模块和功能。
单元测试框架
unittest 框架是一个 Python 测试框架,它基于 Kent Beck 和 Erich Gamma 开发的 XUnit 框架设计模式。它也被称为 PyUnit。unittest 框架通常用于基于自动化测试用例生成报告。
在这个框架中,测试用例是在小的独立单元中测试的(比如函数、方法、类等等)。)来确定 web 元素或网页测试的正确性。通过将类定义为方法并使用断言函数,这些测试以小块或小单元的形式进行。
在开始编写代码之前,您需要了解 unittest 框架支持的以下组件。
-
一个测试夹具执行一个或多个测试用例以及相关的清理动作。创建代理或临时数据库,在服务器上启动一个进程,或者创建新的目录都是文本设备的例子。
-
在测试用例模块中,测试小的单个单元。这些单元与要测试的 web 元素相关。unittest 框架包含一个基类和用于创建新测试用例的测试用例。
-
一个测试套件集合了多个测试用例。它也可以是测试套件的组合。测试套件的执行与测试用例相同。
-
一个测试运行器帮助运行所有的测试用例及其相关的结果。runner 可以与接口集成,比如一个图形、文本或者一个指示测试用例返回值的特殊值。
-
一个测试报告是一个测试用例的生成结果或输出(即是否通过或失败)。测试用例的执行时间以一种系统的方式被安排来生成报告。这些细节在给客户的报告中总结。
测试用例 2:单元测试
首先,需要使用 Python 中的 pip 下载 unittest 库。unittest 框架代码有几个实例可以合并到一个测试用例中。
设置( )
setUp()
方法初始化运行测试用例所需的设置。它在测试用例的开始运行。测试用例的数量决定了要执行的setUp()
方法。例如,如果有十个测试用例,那么setUp()
方法在任何测试用例之前被执行十次。此方法配置测试用例的初始阶段,例如设置 web 驱动程序及其相关组件。
import unittest
from selenium import webdriver
class Test(unittest.TestCase):
#setUp Class method
def setUp(self):
self.driver=webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
print("Firefox Browser Opened")
def test_apress(self):
self.driver.get("https://apress.com")
print("Apress")
def test_google(self):
self.driver.get("https://google.com")
print("Google")
def test_facebook(self):
self.driver.get("https://facebook.com")
print("Facebook")
def test_twitter(self):
self.driver.get("https://twitter.com")
print("Twitter")
if __name__ =="__main__":
unittest.main()
当同一个 web 应用或 web 页面有多个测试用例时,setUp()
方法是有益的。这减少了测试前所需的初始配置或设置。
拆卸( )
在每个测试用例执行之后,执行tearDown()
方法。它是 unittest 中只陈述一次的类方法。它为 unittest 程序中可用的每个测试用例执行。
import unittest
from selenium import webdriver
class Test(unittest.TestCase):
def setUp(self):
self.driver=webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
print("Opened Firefox Browser")
def test_apress(self):
self.driver.get("https://apress.com")
print("Apress")
def tearDown(self):
self.driver.quit()
print("Quit Browser")
if __name__ =="__main__":
unittest.main()
这个方法包含了一些动作,比如关闭 web 驱动或者浏览器,注销或者任何与测试用例相关的关闭动作。无论测试用例结果如何(即通过/失败),一旦执行了setUp()
方法,就执行tearDown()
方法。
Note
在 unittest 的同一个测试类中,一个测试用例可以同时包含 setUp()和 tearDown()方法。
setUpClass
setUpClass
是 unittest 中的一个类,它在任何setUp
或tearDown
函数或同一测试类中出现的任何测试用例之前执行。包含此方法的类只执行它一次,并且它作为单个参数传递。setUpClass
有一个名为@classmethod
的类,在setUp()
函数之前已经声明。
import unittest
from selenium import webdriver
#Class Setup
class Test(unittest.TestCase):
@classmethod
def setUpClass(suc):
suc.driver=webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
print("Open Browser using setUpClass method")
def test_apress(self):
self.driver.get("https://apress.com")
print("Open Apress Site")
if __name__ =="__main__":
unittest.main()
在setUpClass
中setUp()
功能不是强制的。如果这个类执行失败,它会抛出一个异常,并且其中的测试用例or tearDown()
函数不会执行。
tearDownClass
在setUpClass
之后执行tearDownClass
类,所有相关的测试用例出现在同一个测试类中。这个类在退出程序之前执行一次。
import unittest
from selenium import webdriver
#Class Setup
class Test(unittest.TestCase):
@classmethod
def setUpClass(suc):
suc.driver=webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
print("Open Browser using setUpClass method")
def test_apress(self):
self.driver.get("https://apress.com")
print("Open Apress Site")
@classmethod
def tearDownClass(suc):
suc.driver.quit()
print("Close Browser using tearDownClass method")
if __name__ =="__main__":
unittest.main()
不管setUpClass
方法如何,都可以用这个方法。
下面的简单测试案例展示了所有类和函数的一个例子。
setUpModuleandtearDownModule
在 Selenium 上有两个可用的 Python 模块。setUpModule
的执行发生在开始,teardownModule
的执行发生在结束。这两个模块是最近添加到 unittest 框架中的。
import unittest
from selenium import webdriver
class Test(unittest.TestCase):
#Class setup
@classmethod
def setUpClass(suc):
suc.driver=webdriver.Firefox(executable_path=r'C:\Users\ADMIN\Desktop\geckodriver.exe')
print("Open Browser using setUpClass method")
def setUp(self):
print("Execute setUp")
#test case
def test_apress(self):
self.driver.get("https://apress.com")
print("Executing Test Case: Open Apress Site")
def tearDown(self):
print("Execute tearDown")
@classmethod
def tearDownClass(suc):
suc.driver.quit()
print("Close Browser using tearDownClass method")
#Two Modules
def setUpModule():
print("Executes setUpModule")
def tearDownModule():
print("Executes tearDownModule")
if __name__ =="__main__":
unittest.main()
在程序中,首先打印setUpModule()
中的打印语句,然后打印setUpClass()
、setUp()
、test_apress()
、tearDown()
、tearDownClass()
,最后打印tearDownModule()
。
测试执行顺序
由于定义了不同的模块、类、函数和测试用例,所以了解 unittest 框架中的执行顺序非常重要。执行顺序是由模块、类和函数的优先级决定的,它们的定义与程序中的位置无关。一个测试用例的整个执行流程如图 12-1 所示。
图 12-1
单元测试框架中的执行顺序
在 unittest 中,测试用例的执行顺序默认为字母顺序。为了区分优先级,您可以为所有的测试用例定义相同的名称,然后为每个用例定义一个顺序号;例如,test1、test2、test3、test4 等等。
Note
如果有多个测试用例,那么它们将按字母顺序执行。
测试工具比较
许多测试工具可以与 Selenium 上的 Python 一起使用,以生成报告和测试 web 应用。其中一些在表 12-1 中有所介绍。
表 12-1
Python 中的测试工具
|测试工具
|
种类
|
许可证类型
|
描述
|
| --- | --- | --- | --- |
| DocTest | 单元测试 | 免费软件 | 基于 Python 解释器的输出生成测试用例 |
| Nose2 | 单元测试 | 免费软件 | nose 测试框架的继承者扩展了鼻子框架以外的功能;非常容易理解 |
| Pytest | 单元测试 | 免费软件 | 一个初学者友好的工具,支持与 unittest 和 nose 的集成易于构建的小型测试可以扩展到复杂的功能测试 |
| 机器人 | 验收测试 | 免费软件 | 验收测试驱动开发(ATDD)和机器人过程自动化(RPA)的通用框架提供简单的语法;易于与其他框架一起实现 |
| 作证 | 单元测试 | 免费软件 | 基于 Python 的测试插件,提供更多与报告相关的功能和模块提供了 unittest 和 nose 之外的功能 |
摘要
这最后一章解释了使用不同方法得到相同结果的测试用例。unitttest 框架也被 Google 用来自动化测试用例。该框架详细阐述了基本术语和模块。每个模块都有一个与之相关的测试示例。当所有的模块被组合在一个测试用例中时,每个模块执行的顺序形成了一个流动的模式。我们用 Python Selenium 支持的不同测试工具的比较结束了这一章。