📅  最后修改于: 2020-11-06 05:25:34             🧑  作者: Mango
Pytest是一个基于Python的测试框架,用于编写和执行测试代码。在当今的REST服务中,pytest主要用于API测试,即使我们可以使用pytest编写简单到复杂的测试,即我们可以编写代码来测试API,数据库,UI等。
Pytest的优点如下-
Pytest可以并行运行多个测试,从而减少了测试套件的执行时间。
如果没有明确提及,Pytest有自己的方法来自动检测测试文件和测试功能。
Pytest允许我们在执行过程中跳过测试的子集。
Pytest允许我们运行整个测试套件的一部分。
Pytest是免费和开源的。
由于pytest语法简单,因此非常容易上手。
在本教程中,我们将通过示例程序解释pytest的基础知识。
在本章中,我们将学习如何安装pytest。
要开始安装,请执行以下命令-
pip install pytest == 2.9.1
我们可以安装任何版本的pytest。在这里,2.9.1是我们正在安装的版本。
要安装最新版本的pytest,请执行以下命令-
pip install pytest
使用以下命令确认安装,以显示pytest的帮助部分。
pytest -h
在不提及文件名的情况下运行pytest将在当前目录和子目录中运行所有格式为test _ *。py或* _test.py的文件。 Pytest自动将那些文件标识为测试文件。我们可以通过显式提及pytest来运行其他文件名。
Pytest要求测试函数名称以test开头。 pytest不将格式不是test *的函数名视为测试函数。我们不能明确地让pytest将不是以test开头的任何函数视为test函数。
我们将在后续章节中了解测试的执行。
现在,我们将从第一个pytest程序开始。我们将首先创建一个目录,从而在该目录中创建测试文件。
让我们按照下面显示的步骤操作-
创建一个名为Automation的新目录,并在命令行中导航到该目录。
创建一个名为test_square.py的文件,并将以下代码添加到该文件中。
import math
def test_sqrt():
num = 25
assert math.sqrt(num) == 5
def testsquare():
num = 7
assert 7*7 == 40
def tesequality():
assert 10 == 11
使用以下命令运行测试-
pytest
上面的命令将生成以下输出-
test_square.py .F
============================================== FAILURES
==============================================
______________________________________________ testsquare
_____________________________________________
def testsquare():
num=7
> assert 7*7 == 40
E assert (7 * 7) == 40
test_square.py:9: AssertionError
================================= 1 failed, 1 passed in 0.06 seconds
=================================
请参阅结果的第一行。它显示文件名和结果。 F表示测试失败,而dot(。)表示测试成功。
在此之下,我们可以看到失败的测试的详细信息。它将显示测试失败的语句。在我们的示例中,将7 * 7与40进行相等比较,这是错误的。最后,我们可以看到测试执行摘要,1个失败和1个通过。
tesequality函数未执行,因为pytest的名称不是test *格式,因此不会将其视为测试。
现在,执行以下命令并再次查看结果-
pytest -v
-v增加详细程度。
test_square.py::test_sqrt PASSED
test_square.py::testsquare FAILED
============================================== FAILURES
==============================================
_____________________________________________ testsquare
_____________________________________________
def testsquare():
num = 7
> assert 7*7 == 40
E assert (7 * 7) == 40
test_square.py:9: AssertionError
================================= 1 failed, 1 passed in 0.04 seconds
=================================
现在,结果对于失败的测试和通过的测试更具解释性。
注意-pytest命令将在当前目录和子目录中执行所有格式为test_ *或* _test的文件。
在本章中,我们将学习如何执行单个测试文件和多个测试文件。我们已经创建了一个测试文件test_square.py 。使用以下代码创建一个新的测试文件test_compare.py-
def test_greater():
num = 100
assert num > 100
def test_greater_equal():
num = 100
assert num >= 100
def test_less():
num = 100
assert num < 200
现在要运行所有文件(此处为2个文件)中的所有测试,我们需要运行以下命令-
pytest -v
上面的命令将从test_square.py和test_compare.py运行测试。输出将生成如下-
test_compare.py::test_greater FAILED
test_compare.py::test_greater_equal PASSED
test_compare.py::test_less PASSED
test_square.py::test_sqrt PASSED
test_square.py::testsquare FAILED
================================================ FAILURES
================================================
______________________________________________ test_greater
______________________________________________
def test_greater():
num = 100
> assert num > 100
E assert 100 > 100
test_compare.py:3: AssertionError
_______________________________________________ testsquare
_______________________________________________
def testsquare():
num = 7
> assert 7*7 == 40
E assert (7 * 7) == 40
test_square.py:9: AssertionError
=================================== 2 failed, 3 passed in 0.07 seconds
===================================
要从特定文件执行测试,请使用以下语法-
pytest -v
现在,运行以下命令-
pytest test_compare.py -v
上面的命令将仅从文件test_compare.py执行测试。我们的结果将是-
test_compare.py::test_greater FAILED
test_compare.py::test_greater_equal PASSED
test_compare.py::test_less PASSED
============================================== FAILURES
==============================================
____________________________________________ test_greater
____________________________________________
def test_greater():
num = 100
> assert num > 100
E assert 100 > 100
test_compare.py:3: AssertionError
================================= 1 failed, 2 passed in 0.04 seconds
=================================
在实际情况下,我们将有多个测试文件,并且每个文件将具有许多测试。测试将涵盖各种模块和功能。假设我们只想运行一组特定的测试;我们如何去做?
Pytest提供了两种方法来运行测试套件的子集。
在后面的章节中,我们将通过示例解释这两个问题。
要执行包含名称字符串的测试,我们可以使用以下语法-
pytest -k -v
-k
现在,运行以下命令-
pytest -k great -v
这将执行所有名称中带有单词“ great”的测试名称。在这种情况下,它们是test_greater()和test_greater_equal() 。请参阅下面的结果。
test_compare.py::test_greater FAILED
test_compare.py::test_greater_equal PASSED
============================================== FAILURES
==============================================
____________________________________________ test_greater
____________________________________________
def test_greater():
num = 100
> assert num > 100
E assert 100 > 100
test_compare.py:3: AssertionError
========================== 1 failed, 1 passed, 3 deselected in 0.07 seconds
==========================
在结果中,我们可以看到取消选择了3个测试。这是因为这些测试名称中没有包含单词great 。
注–测试函数的名称仍应以’test’开头。
在本章中,我们将学习如何使用标记对测试进行分组。
Pytest允许我们在测试功能上使用标记。标记用于设置各种功能/属性以测试功能。 Pytest提供了许多内置标记,例如xfail,skip和parametrize。除此之外,用户可以创建自己的标记名称。使用下面给出的语法将标记应用于测试-
@pytest.mark.
要使用标记,我们必须在测试文件中导入pytest模块。我们可以为测试定义自己的标记名,然后使用这些标记名运行测试。
要运行标记的测试,我们可以使用以下语法-
pytest -m -v
-m <标记名>表示要执行的测试的标记名。
使用以下代码更新我们的测试文件test_compare.py和test_square.py 。我们正在定义3个标记-伟大,正方形,其他。
import pytest
@pytest.mark.great
def test_greater():
num = 100
assert num > 100
@pytest.mark.great
def test_greater_equal():
num = 100
assert num >= 100
@pytest.mark.others
def test_less():
num = 100
assert num < 200
import pytest
import math
@pytest.mark.square
def test_sqrt():
num = 25
assert math.sqrt(num) == 5
@pytest.mark.square
def testsquare():
num = 7
assert 7*7 == 40
@pytest.mark.others
def test_equality():
assert 10 == 11
现在要运行标记为其他的测试,请运行以下命令-
pytest -m others -v
请参阅下面的结果。它运行了标记为其他的2个测试。
test_compare.py::test_less PASSED
test_square.py::test_equality FAILED
============================================== FAILURES
==============================================
___________________________________________ test_equality
____________________________________________
@pytest.mark.others
def test_equality():
> assert 10 == 11
E assert 10 == 11
test_square.py:16: AssertionError
========================== 1 failed, 1 passed, 4 deselected in 0.08 seconds
==========================
同样,我们也可以使用其他标记进行测试-很好,比较
夹具是函数,将在应用它的每个测试函数之前运行。夹具用于向测试提供一些数据,例如数据库连接,要测试的URL和某种输入数据。因此,我们不必为每个测试运行相同的代码,而是可以将fixture函数附加到测试,它将在执行每个测试之前运行并将数据返回给测试。
一个函数被标记为固定装置-
@pytest.fixture
测试函数可以通过提及灯具名称作为输入参数来使用灯具。
创建文件test_div_by_3_6.py并将以下代码添加到其中
import pytest
@pytest.fixture
def input_value():
input = 39
return input
def test_divisible_by_3(input_value):
assert input_value % 3 == 0
def test_divisible_by_6(input_value):
assert input_value % 6 == 0
在这里,我们有一个名为input_value的夹具函数,该函数将输入提供给测试。要访问灯具函数,测试必须提及灯具名称作为输入参数。
Pytest在执行测试时,将夹具名称作为输入参数。然后执行夹具函数,并将返回值存储到输入参数中,供测试使用。
使用以下命令执行测试-
pytest -k divisible -v
上面的命令将产生以下结果-
test_div_by_3_6.py::test_divisible_by_3 PASSED
test_div_by_3_6.py::test_divisible_by_6 FAILED
============================================== FAILURES
==============================================
________________________________________ test_divisible_by_6
_________________________________________
input_value = 39
def test_divisible_by_6(input_value):
> assert input_value % 6 == 0
E assert (39 % 6) == 0
test_div_by_3_6.py:12: AssertionError
========================== 1 failed, 1 passed, 6 deselected in 0.07 seconds
==========================
但是,该方法有其自身的局限性。在测试文件内定义的夹具函数仅在测试文件内具有作用域。我们不能在另一个测试文件中使用该灯具。为了使夹具可用于多个测试文件,我们必须在名为conftest.py的文件中定义夹具函数。 conftest.py将在下一章中进行说明。
我们可以在此文件中定义灯具功能,以使它们可以跨多个测试文件访问。
创建一个新文件conftest.py并将以下代码添加到其中-
import pytest
@pytest.fixture
def input_value():
input = 39
return input
编辑test_div_by_3_6.py删除固定函数-
import pytest
def test_divisible_by_3(input_value):
assert input_value % 3 == 0
def test_divisible_by_6(input_value):
assert input_value % 6 == 0
创建一个新文件test_div_by_13.py-
import pytest
def test_divisible_by_13(input_value):
assert input_value % 13 == 0
现在,我们有文件test_div_by_3_6.py和test_div_by_13.py利用在conftest.py定义的夹具。
通过执行以下命令来运行测试-
pytest -k divisible -v
上面的命令将产生以下结果-
test_div_by_13.py::test_divisible_by_13 PASSED
test_div_by_3_6.py::test_divisible_by_3 PASSED
test_div_by_3_6.py::test_divisible_by_6 FAILED
============================================== FAILURES
==============================================
________________________________________ test_divisible_by_6
_________________________________________
input_value = 39
def test_divisible_by_6(input_value):
> assert input_value % 6 == 0
E assert (39 % 6) == 0
test_div_by_3_6.py:7: AssertionError
========================== 1 failed, 2 passed, 6 deselected in 0.09 seconds
==========================
测试将在同一文件中查找夹具。由于在文件中找不到固定装置,它将在conftest.py文件中检查固定装置。找到它后,将调用fixture方法,并将结果返回到测试的输入参数。
完成测试的参数化以针对多组输入运行测试。我们可以通过使用以下标记来做到这一点-
@pytest.mark.parametrize
将以下代码复制到名为test_multiplication.py的文件中-
import pytest
@pytest.mark.parametrize("num, output",[(1,11),(2,22),(3,35),(4,44)])
def test_multiplication_11(num, output):
assert 11*num == output
在这里,测试将输入乘以11,然后将结果与预期输出进行比较。该测试有4组输入,每组都有2个值-一组是要乘以11的数字,另一组是预期结果。
通过运行以下命令执行测试-
Pytest -k multiplication -v
上面的命令将生成以下输出-
test_multiplication.py::test_multiplication_11[1-11] PASSED
test_multiplication.py::test_multiplication_11[2-22] PASSED
test_multiplication.py::test_multiplication_11[3-35] FAILED
test_multiplication.py::test_multiplication_11[4-44] PASSED
============================================== FAILURES
==============================================
_________________ test_multiplication_11[3-35] __________________
num = 3, output = 35
@pytest.mark.parametrize("num, output",[(1,11),(2,22),(3,35),(4,44)])
def test_multiplication_11(num, output):
> assert 11*num == output
E assert (11 * 3) == 35
test_multiplication.py:5: AssertionError
============================== 1 failed, 3 passed, 8 deselected in 0.08 seconds
==============================
在本章中,我们将学习Pytest中的Skip和Xfail测试。
现在,考虑以下情况-
在这些情况下,我们可以选择xfail测试或跳过测试。
Pytest将执行xfailed测试,但不会被视为部分失败或通过测试。即使测试失败,也不会打印这些测试的详细信息(请记住pytest通常会打印失败的测试详细信息)。我们可以使用以下标记使测试失败-
@pytest.mark.xfail
跳过测试意味着将不会执行测试。我们可以使用以下标记跳过测试-
@pytest.mark.skip
稍后,当测试变得有意义时,我们可以删除标记。
编辑test_compare.py我们已经有包括xfail并跳过标记-
import pytest
@pytest.mark.xfail
@pytest.mark.great
def test_greater():
num = 100
assert num > 100
@pytest.mark.xfail
@pytest.mark.great
def test_greater_equal():
num = 100
assert num >= 100
@pytest.mark.skip
@pytest.mark.others
def test_less():
num = 100
assert num < 200
使用以下命令执行测试-
pytest test_compare.py -v
执行后,上述命令将产生以下结果-
test_compare.py::test_greater xfail
test_compare.py::test_greater_equal XPASS
test_compare.py::test_less SKIPPED
============================ 1 skipped, 1 xfailed, 1 xpassed in 0.06 seconds
============================
在实际情况下,一旦准备好部署新版本的代码,便会首先将其部署到预生产/登台环境中。然后在其上运行测试套件。
仅当测试套件通过时,该代码才有资格部署到生产中。如果存在测试失败(无论是一次还是多次),则该代码尚未准备就绪。
因此,如果我们想在n次测试失败后立即停止执行测试套件,该怎么办。这可以在pytest中使用maxfail完成。
在n次测试失败后立即停止执行测试套件的语法如下-
pytest --maxfail =
使用以下代码创建文件test_failure.py。
import pytest
import math
def test_sqrt_failure():
num = 25
assert math.sqrt(num) == 6
def test_square_failure():
num = 7
assert 7*7 == 40
def test_equality_failure():
assert 10 == 11
所有3个测试都将在执行此测试文件时失败。在这里,我们将在一次失败后通过以下方式停止测试的执行:
pytest test_failure.py -v --maxfail = 1
test_failure.py::test_sqrt_failure FAILED
=================================== FAILURES
=================================== _______________________________________
test_sqrt_failure __________________________________________
def test_sqrt_failure():
num = 25
> assert math.sqrt(num) == 6
E assert 5.0 == 6
E + where 5.0 = (25)
E + where = math.sqrt
test_failure.py:6: AssertionError
=============================== 1 failed in 0.04 seconds
===============================
在上面的结果中,我们可以看到执行一次失败就停止了。
默认情况下,pytest按顺序运行测试。在实际情况下,一个测试套件将具有许多测试文件,并且每个文件将具有一堆测试。这将导致大量的执行时间。为了克服这个问题,pytest为我们提供了并行运行测试的选项。
为此,我们需要首先安装pytest-xdist插件。
通过运行以下命令安装pytest-xdist-
pip install pytest-xdist
现在,我们可以使用语法pytest -n
pytest -n 3
-n
当只有几个测试要运行时,我们不会有太多时间差。但是,当测试套件很大时,这很重要。
我们可以在xml文件中生成测试执行的详细信息。这个xml文件主要在我们有一个显示测试结果的仪表板的情况下很有用。在这种情况下,可以解析xml以获取执行的详细信息。
现在,我们将从test_multiplcation.py执行测试,并通过运行生成xml
pytest test_multiplication.py -v --junitxml="result.xml"
现在我们可以看到result.xml是使用以下数据生成的-
failure message = "assert (11 * 3) == 35">num = 3, output = 35
@pytest.mark.parametrize("num,
output",[(1,11),(2,22),(3,35),(4,44)])
def test_multiplication_11(num, output):>
assert 11*num == output
E assert (11 * 3) == 35
test_multiplication.py:5: AssertionErro
在这里,标签
标记
在本pytest教程中,我们涵盖了以下领域-
本教程向您介绍pytest框架。现在您应该可以开始使用pytest编写测试了。
作为一个好习惯-