使用 Pytest 和 Selenium WebDriver 进行测试自动化
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
如今,开发者面临的挑战之一是确保其网站/Web应用程序能够在不同的设备、浏览器和操作系统/平台上无缝运行。跨浏览器测试在此过程中发挥着至关重要的作用,因为它有助于测试不同组合下的兼容性。根据目标市场,开发和产品团队需要制定一个关于浏览器兼容性测试各项活动的计划。
Selenium – 简介及 WebDriver 接口
就Web应用程序测试而言,目前有多种Web框架可用于自动化执行跨不同浏览器的测试。Selenium是一个非常流行的框架,主要用于Web应用程序的自动化测试。它是一个开源工具,可用于在Chrome、Firefox、Opera、Microsoft Edge等主流浏览器上执行Web测试。如果需要在Internet Explorer(最新版本或旧版本)上执行测试,也可以使用该框架。
Selenium WebDriver 被认为是 Selenium 框架的核心组件之一。Selenium WebDriver API 是一系列开源 API 和特定语言绑定的集合,它接收命令并将其发送到浏览器(测试对象)。负责开发测试的人员无需关心 Web 浏览器的“架构细节或其他技术规范”,因为 WebDriver 充当了测试套件/测试用例与Web 浏览器之间的接口(通过特定于浏览器的 WebDriver 实现)。Selenium WebDriver 支持多种编程语言,例如 Python、C#、Ruby、Perl、Java等。下图展示了Selenium WebDriver接口的简化视图。我们已在之前的文章中深入探讨了 Selenium WebDriver 的架构。
Pytest 测试框架 – 简介及优势
Python 语言拥有多个测试框架,可以简化 Web 应用程序测试的工作,其中 unittest 和 pytest 是最常用的框架。unittest 是 Python 标准库的一部分,包含在 Python 安装包中。如果要使用 pytest 和 Selenium WebDriver 进行自动化测试,则需要单独安装 pytest。pytest 比 unittest 框架更受欢迎,以下是 pytest 框架的一些优势。
- 可供开发团队、测试团队、实践测试驱动开发(TDD)的团队以及开源项目使用。
- 可用于应用程序和库的简单以及复杂的功能测试用例。
- 可以轻松地将现有测试套件移植到 pytest,以便使用 pytest 和 Selenium WebDriver 执行测试自动化。
- 它与其他测试框架(如 unittest 和 nose)兼容,因此切换到该框架非常容易。
- 支持参数化,这使得只需一个简单的标记即可使用“不同的配置”执行相同的测试。因此,您可以编写出更高效的测试用例/测试套件,并减少“重复代码的编写”。
- 提供有关故障场景的更详细信息的断言数量。
- 支持测试夹具和类。使用测试夹具,可以轻松地在整个模块/会话/函数/类中提供通用的测试对象。后续章节将更详细地介绍测试夹具和类。
- 文档齐全且内容最新。
- 通过 xdist 支持,可以并行化测试用例。
既然您已经了解了 pytest 相对于其他测试框架的优势,那么让我们详细了解一下 pytest 框架以及如何将其与 Selenium WebDriver 框架一起使用,以便对 Web 应用程序执行自动化跨浏览器测试。
总而言之,Pytest 是一个软件测试框架,它可以轻松创建简单而又可扩展的测试用例。
嘿,你是不是在寻找Hexo Testing?它可以测试你基于 Hexo CSS 框架的网站在 3000 多种不同的桌面和移动浏览器上的兼容性。
使用 Pytest 进行测试自动化 – 安装和入门
如前所述,pytest 不是 Python 标准安装的一部分,需要单独安装。要安装 pytest,您应该在提示符/终端中执行以下命令:pip install –U pytest
安装完成后,您可以通过输入以下命令来验证安装是否成功:
pytest --version
下面显示的是在 Linux 和 Windows 机器上执行上述命令的输出结果。
PyCharm 是一款流行的 IDE,常用于 pytest 开发。您可以从这里安装适用于 Windows、Linux 或 macOS 的 PyCharm 教育版。我们这里使用的是 Windows 版 PyCharm 进行开发。安装 PyCharm 后,请确保默认测试运行器为 pytest。要更改默认测试运行器,请依次点击“文件”->“设置”->“工具”->“Python 集成工具”,然后更改默认测试运行器,以便使用 pytest 和 Selenium WebDriver 执行自动化测试。
现在 PyCharm 教育版已安装完毕,默认测试运行器也已设置为 pytest。接下来,您需要安装 Python 的 Selenium 包,才能使用 pytest 和 Selenium WebDriver 执行自动化测试。要安装 Selenium,请在 PyCharm 的终端中运行以下命令。
pip install -U selenium ( Syntax – pip install –U )
下面显示的是命令执行的快照。
现在您的开发环境已准备就绪,即 PyCharm 已安装好,可以使用 pytest 和 Selenium 执行自动化测试,接下来我们将了解 pytest 的一些特性和方面。
Pytest – 用法、退出代码和编译
pytest 和 py.test 可以互换使用。要获取 pytest 可使用的参数信息,可以在终端中执行以下命令。
pytest --help #此命令用于获取有关 pytest 命令可用选项的帮助信息 # 灯具详情 pytest --fixtures #显示可用的内置函数参数
当执行 pytest 代码时,会产生以下退出代码之一。
| 退出代码 | 描述 |
|---|---|
| 0 | 测试用例/测试套件已成功执行,最终结果为“通过”。 |
| 1 | 测试用例/测试套件已执行,但部分测试失败。 |
| 2 | 用户已停止测试执行。 |
| 3 | 执行测试时发生未知错误 |
| 4 | pytest 命令使用不当 |
| 5 | 未收集任何检测样本。 |
包含 pytest 代码的文件必须命名为 test_*.py 或 *_test.py。要编译并执行 pytest 源代码,以便使用 pytest 和 Selenium WebDriver 执行自动化测试,您可以在终端中使用以下命令。
pytest --verbose --capture=no
让我们来看一些使用 pytest 进行测试自动化的示例。我们从一个非常简单的例子开始——test_pytest_example_1.py(顾名思义)。
#pytest 实际应用 – test_pytest_example_1.py def function_1(var): 返回变量 + 1 def test_success(): 断言 function_1(4) == 5 def test_failure(): 断言 function_1(2) == 5
在上面的代码片段中,我们创建了一个名为 function_1 的函数,它接受一个名为 var 的参数。有两个测试用例:test_success() 和 test_failure()。这些测试用例按顺序执行,并在每次执行测试用例时发出断言。使用以下命令编译代码。
pytest --verbose --capture=no test_pytest_example_1.py
从输出结果可以看出,第一个测试用例的结果为通过(以蓝色显示),第二个测试用例的结果为失败(以红色显示)。
pytest 使用 Python 中提供的 assert 语句来验证结果,它会输出可用于验证和调试的有意义的信息。pytest.raises 通常用于抛出异常,以下示例展示了如何计算一个数的阶乘。在一个测试用例中,将一个负数作为输入传递给阶乘函数,结果抛出了 AssertionError 异常。
factorial_example.py – 包含使用递归计算输入数字阶乘的实现。在计算阶乘之前,会先检查输入参数。如果输入数字为负数,则会引发断言异常。
def factorial_function(number):
检查输入的数字是否为正数,如果不是,则执行以下操作:
# 积极,提出断言
断言 number >= 0 且 type(number) 为 int,则“输入无法识别”。
如果数字等于 0:
返回 1
别的:
# 计算阶乘的递归函数
返回 number * factorial_function(number – 1)
test_factorial_example.py – 使用阶乘功能的 pytest 实现。实现了三个测试用例:test_standard_library(将 factorial_function 的输出与 math.factorial 模块的输出进行比较)、test_negative_number(当输入数字为负数时引发断言)和 test_negative_number(将 factorial_function 的输出结果与特定值进行比较)。
# 导入实现所需的必要模块/包
导入 pytest
导入数学
from factorial_example import factorial_function
def test_factorial_functionality():
print("在 test_factorial_functionality 内部")
断言 factorial_function(0) == 1
断言 factorial_function(4) == 24
def test_standard_library():
print("在 test_standard_library 内部")
for i in range(5):
# 验证阶乘计算是否正确
通过对照标准检查结果
# 库 - math.factorial()
断言 math.factorial(i) == factorial_function(i)
def test_negative_number():
print("在 test_negative_number 内部")
# 如果断言错误,此测试用例将通过
# 被提升。在这种情况下,输入的数字为负数。
因此,测试用例通过。
使用 pytest.raises(AssertionError):
factorial_function(-10)
您可以使用命令 `py.test --capture=no test_factorial_example.py` 在命令行或 PyCharm IDE 的终端中执行代码。如截图所示,所有测试用例均已通过,并且“print statement”下的日志已输出到控制台。
使用 Pytest 进行测试自动化——测试夹具(用法和实现)
假设你需要对一个包含组织员工信息的数据库执行某些 MySQL 查询。查询执行时间取决于数据库中的记录数(即员工数)。在执行查询之前,必须先进行必要的数据库连接操作,并将返回的句柄用于后续涉及该数据库的操作。随着记录数的增加,数据库操作可能会消耗大量 CPU 资源,因此应避免重复执行。有两种方法可以解决这个问题。
- 借助经典的 xunit 风格安装和拆卸方法。
- 使用固定装置(推荐)。
unittest 已经支持 xunit 风格的 fixtures,但 pytest 处理 fixtures 的方式要好得多。Fixtures 是一组需要在测试开始前设置并在测试执行完毕后清理的资源。它相比传统的 setup 和 teardown 函数实现方式有很多改进。使用 fixtures 的主要优势包括:
- 开发者可以设置测试用例的生命周期和作用域。已实现测试用例的作用域可以是模块、函数、类或整个项目。
- 设备采用模块化设计,因此无需学习即可上手。
- 函数级测试用例能够提高测试代码的可读性和一致性,从而降低维护难度。
- 固定装置函数利用了称为“依赖注入”的面向对象编程设计概念,其中固定装置函数扮演注入器的角色,而测试函数则被视为固定装置对象的使用者。
- 每个 fixture 都有一个名称(类似于函数名称),该名称又可以调用其他 fixture 函数。
- 测试夹具可以重复使用,既可用于简单的单元测试,也可用于测试复杂的用例。
自 3.5 版本发布以来,在实例化方面,作用域较高的 fixture 的优先级高于作用域较低的 fixture。作用域较高的 fixture 包括会话,作用域较低的 fixture 包括类、函数等。您甚至可以“参数化”这些 fixture 函数,以便在执行依赖测试时多次执行它们。Fixed 参数化已被广泛用于编写详尽的测试函数。以下是使用 pytest 进行测试自动化的简单代码,其中即使在执行 test_2 时,也会调用“资源 1”的 setup() 和 teardown() 函数。由于这是一个简单的实现(计算量较少),即使“调用了不必要的 setup 和模块”,也不会造成太多开销,但如果涉及任何“CPU 密集型”操作(例如数据库连接),则可能会影响整体代码性能:
#导入所有必要的模块
导入 pytest
def resource_1_setup():
print('资源 1 的设置已调用')
def resource_1_teardown():
print('调用资源 1 的拆卸程序')
def setup_module(module):
print('\n模块设置被调用')
resource_1_setup()
def teardown_module(module):
print('\n模块拆卸已调用')
resource_1_teardown()
def test_1_using_resource_1():
print('使用资源 1 的测试 1')
def test_2_not_using_resource_1():
print('\n测试 2 不需要资源 1')
在终端上调用以下命令来执行测试用例“test_2_not_using_resource_1”。
pytest --capture=no --verbose test_fixtures.py::test_2_not_using_resource_1
从输出结果 [Filename – Pytest-Fixtures-problem.png] 可以看出,即使执行了 'test_2' 测试,'resource 1' 的 fixture 函数也被不必要地调用了。这个问题可以通过使用 fixture 来解决;我们将在接下来的示例中进行探讨。
如下例所示,我们定义了 fixture 函数 resource_1_setup()(类似于 xunit 风格实现中的 setup 函数)和 resource_1_teardown()(类似于 xunit 风格实现中的 teardown 函数)。该 fixture 函数具有“模块作用域”,使用 @pytest.fixture(scope='module')。
#导入所有必要的模块
导入 pytest
#实现具有模块作用域的 fixture
@pytest.fixture(scope='module')
def resource_1_setup(request):
print('\n资源 1 的设置被调用')
def resource_1_teardown():
print('\n调用资源 1 的清理程序')
执行清理代码的另一种方法是使用请求上下文的 addfinalizer 方法。
# 用于注册终结函数的对象。
# 来源 - https://docs.pytest.org/en/latest/fixture.html
request.addfinalizer(resource_1_teardown)
def test_1_using_resource_1(resource_1_setup):
print('测试 1 使用资源 1')
def test_2_not_using_resource_1():
print('\n测试 2 不需要资源 1')
我们通过触发所有测试用例(即 test_1_using_resource_1() 和 test_2_not_using_resource_1())来执行代码。如下面的输出所示 [文件名 – Pytest-Fixtures-all-tests-executed.png],“setup for resource 1”仅在测试用例 1 中调用,而未在测试用例 2 中调用。
现在,我们只执行测试用例 2,即 test_2_not_using_resource_1()。如下面的输出所示 [文件名 – Pytest-Fixtures-only-2-tests-executed.png],由于只执行了测试用例 2,因此“资源 1”的 setup 和 teardown 函数不会被调用。这正是 fixtures 的强大之处,因为它能够消除“重复代码”和“不必要的代码执行”。关于 pytest 中 fixtures 的官方文档可以在这里找到。
嘿,你是不是在寻找HubSpot 测试工具?它可以测试你基于 HubSpot CSS 框架的网站在 3000 多种不同的桌面和移动浏览器上的兼容性。
使用 Pytest 和 Selenium WebDriver 进行测试自动化
在寻找测试自动化框架时,您可能需要一个能够满足所有需求的测试框架,例如单元测试、功能测试、验收测试等等。该框架应该具备记录事件、生成测试报告的功能,并且拥有良好的社区支持。Pytest 完全符合这些要求,并且强烈推荐使用 Pytest 和 Selenium WebDriver 进行测试自动化,因为它学习曲线并不陡峭。
当您计划使用 PyTest 和 Selenium WebDriver 开发自动化测试时,首先需要考虑的是何时加载浏览器。不建议在每次测试后都加载一个新的浏览器实例,因为这并非可扩展的解决方案,并且可能会增加整体测试执行时间。建议在实际测试用例开始之前加载被测浏览器,并在测试完成后立即卸载/关闭浏览器实例。这可以通过使用 PyTest 中的 Fixtures 来实现(详见下文“使用 PyTest 进行自动化测试 - Fixtures(用法和实现)”部分)。如前所述,Fixtures 广泛使用了“依赖注入”的概念,可以在实际测试开始之前加载依赖项。
默认情况下,测试用例的作用域为“函数”,具体取决于需求;您可以将已实现测试用例的作用域更改为模块、会话或类。类似于 C 语言中的“变量生命周期”,测试用例的作用域决定了特定测试用例将被创建多少次。
| 夹具范围 | 解释 |
|---|---|
| 功能 | 测试夹具在每个测试会话中执行/运行一次 |
| 会议 | 整个测试阶段只创建一个测试装置。 |
| 班级 | 每个测试类别只创建一个 fixture。 |
| 模块 | 每个模块仅创建一次夹具 |
测试执行完毕后,您可能希望以报告格式(例如 HTML)捕获测试结果。为此,您需要安装 pytest-html 模块。
pip install pytest-html
以下是命令执行过程中的截图。
现在您已经了解了 pytest fixtures、Selenium 和 Selenium WebDriver 接口,让我们来看一个实际应用示例。在开始实现之前,请确保分别从这里和这里下载 Geckodriver for Firefox 和 ChromeDriver for Chrome。为了避免提及驱动程序的下载路径/位置,请确保将这些驱动程序放在相应浏览器所在的目录下。在下面的截图中,您可以看到我们已将 Geckodriver.exe 复制到 Firefox 浏览器 (firefox.exe) 所在的目录下。
现在配置已经完成,让我们开始实现吧。首先导入所有必要的模块,以避免出错。在本例中,导入的模块包括 selenium、pytest 和 pytest-html。两个 fixture 函数——driver_init() 和 chrome_driver_init()——的作用域为“class”。如 fixture 函数 driver_init() 所示,它使用 GeckoDriver 创建了一个 Firefox 实例;而在 chrome_driver_init() 中,它使用 ChromeDriver 创建了一个 Chrome 浏览器实例。yield 包含 teardown 的实现,即 yield 内部的代码负责执行清理工作。测试用例使用类进行分组,在本例中,有两个重要的类:Test_URL() 和 Test_URL_Chrome()。这些类使用了通过 mark.usefixtures [@pytest.mark.usefixtures(“driver_init”)] 实现的 fixture。该测试用例执行一个简单的测试,即调用相应的浏览器(Firefox/Chrome)并打开提供的 URL,例如https://www.lambdatest.com/。文件名:test_selenium_webdriver-2.py
# 导入执行所需的“模块”
导入 pytest
导入 pytest_html
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
从时间导入睡眠
Firefox 的 #Fixture
@pytest.fixture(scope="class")
def driver_init(request):
ff_driver = webdriver.Firefox()
request.cls.driver = ff_driver
屈服
ff_driver.close()
#铬合金固定装置
@pytest.fixture(scope="class")
def chrome_driver_init(request):
chrome_driver = webdriver.Chrome()
request.cls.driver = chrome_driver
屈服
chrome_driver.close()
@pytest.mark.usefixtures("driver_init")
class BasicTest:
经过
class Test_URL(BasicTest):
def test_open_url(self):
self.driver.get("https://www.lambdatest.com/")
print(self.driver.title)
睡眠(5)
@pytest.mark.usefixtures("chrome_driver_init")
class Basic_Chrome_Test:
经过
class Test_URL_Chrome(Basic_Chrome_Test):
def test_open_url(self):
self.driver.get("https://www.lambdatest.com/")
print(self.driver.title)
睡眠(5)
由于我们需要将测试输出保存在 HTML 文件中,因此在执行测试代码时需要使用 `--html=` 参数。以下是使用 pytest 和 Selenium WebDriver 执行自动化测试的完整命令:
py.test.exe --capture=no --verbose --html=pytest_selenium_test_report.html test_selenium_webdriver-1.py
以下是执行输出,测试用例 test_open_url() 针对类 Test_URL 和 Test_URL_Chrome() 执行。测试报告位于 pytest_selenium_test_report.html [图片 – PyTest-Selenium-Output-1.png]。为了更清晰地说明,这里提供一份测试报告。
如上文所述,Firefox 和 Chrome 浏览器的 fixture 函数之间的唯一区别在于“对相应浏览器的设置”。大部分实现对于两个浏览器都是相同的(参见 `Test_URL()` 和 `Test_URL_Chrome()`),因此,通过避免“代码重复”来优化代码至关重要。这可以通过使用“参数化 fixture”来实现。如实现文件 `test_selenium_webdriver-1.py` 所示,主要变化是为 fixture 添加了“参数”,即 `@pytest.fixture(params=["chrome", "firefox"],scope="class")`。根据所使用的浏览器,使用相应的 WebDriver 来调用浏览器。
# 导入执行所需的“模块”
导入 pytest
导入 pytest_html
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
从时间导入睡眠
Firefox 的 #Fixture
@pytest.fixture(params=["chrome", "firefox"],scope="class")
def driver_init(request):
如果 request.param == "chrome":
web_driver = webdriver.Chrome()
如果 request.param == "firefox":
web_driver = webdriver.Firefox()
request.cls.driver = web_driver
屈服
web_driver.close()
@pytest.mark.usefixtures("driver_init")
class BasicTest:
经过
class Test_URL(BasicTest):
def test_open_url(self):
self.driver.get("https://www.lambdatest.com/")
print(self.driver.title)
睡眠(5)
在本例中,我们使用 Chrome 和 Firefox 浏览器,测试用例 Test_URL() 将分别针对每个浏览器执行。如输出所示,该测试用例仅调用一次,参数分别为 'firefox' 和 'chrome'。
嘿,你是不是在找Hugo Testing?它可以测试你基于 Hugo CSS 框架的网站在 3000 多种不同的桌面和移动浏览器上的兼容性。
使用 Pytest、Selenium 和 Lambdatest 进行跨浏览器测试
由于全面的测试需要在不同类型的设备(手机、平板电脑、台式机等)、操作系统(Windows、Linux、macOS、Chrome 等)以及浏览器(例如 Chrome、Firefox、Safari、Opera 等)上进行,因此在本地机器或测试机器上能够执行的测试量始终存在限制。搭建“本地测试环境/测试集群”并非一种可扩展且经济的选择。而 Lambdatest 的云端跨浏览器测试功能可以有效解决这一问题,让您的测试团队能够充分利用其强大的功能。
您可以对 Web 应用程序/网站在不同浏览器(包括旧版本)、设备等上进行手动和自动化的跨浏览器测试。您还可以使用其 Tunnel 功能进行实时测试,该功能允许您从终端访问其测试基础架构。LambdaTest Selenium Automation Grid 使您能够在安全、可靠且可扩展的 Selenium 基础架构上执行端到端自动化测试。您不仅可以利用 LambdaTest Selenium Grid 提高整体代码覆盖率(通过测试),还可以减少执行用 Python 编写的自动化脚本所需的总时间。
结论
使用 Pytest 和 Selenium WebDriver 进行测试自动化是一个非常理想的选择。Pytest 框架功能强大,测试工程师可以利用它轻松实现易于部署且可扩展的测试用例。它既可以用于编写简单场景的测试用例,也可以用于编写高度复杂的场景的测试用例。对于精通 Python、unittest 或其他基于 Python 的测试框架的开发人员/测试人员来说,Pytest 非常容易上手。由于 Pytest 利用了依赖注入等概念,因此源代码的维护成本较低。
如果您正在寻找测试 Web 应用程序或网站的方法,可以使用 pytest 和 Selenium 框架执行自动化测试。随着设备数量的日益增长,针对不同的设备、操作系统和浏览器测试代码变得几乎不可能;而 Lambdatest 的“跨浏览器测试工具”可以解决这个问题,它使您能够轻松地使用 pytest 和 Selenium WebDriver 执行自动化测试。
原文出处:lambdatest.com
相关文章:
文章来源:https://dev.to/lambdatest/test-automation-using-pytest-and-selenium-webdriver-jd8












