Pytest框架使用教程
Pytest框架使用教程
Pytest介绍
Pytest 是一个基于python 的测试框架,用于编写和执行测试代码。
Pytest的优点:
- pytest 可以并行运行多个测试,从而减少测试套件的执行时间。
- 如果没有明确提及,Pytest 有自己的方法来自动检测测试文件和测试函数。
- Pytest 允许我们在执行期间跳过测试的子集。(xfail/skip)
- Pytest 允许我们运行整个测试套件的一个子集。(pytest 文件名称.py -v)
- Pytest 是免费和开源的.
- 由于语法简单,pytest 非常容易上手。
Pytest环境设置
根据版本号安装pytest
pip install pytest == 2.9.1
安装最新版pytest
pip install pytest
确认安装
pytest -h
Pytest识别测试文件和函数
文件名称使用格式:
test_*.py 或 *_test.py (在不指定文件名的情况下运行 pytest 将运行当前目录和子目录中格式为 test_*.py 或 *_test.py 的所有文件)
测试函数名称使用格式:
test_*(pytest 要求测试函数名称以 test 开头)
执行所有测试文件
pytest 或 pytest -v
执行特点文件
pytest 文件名称.py -v
匹配测试名称子字符串执行测试
pytest -k 函数字符串 -v
#例:
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
'''
命令行输入: pytest -k great -v
得:
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
'''
通过标记执行测试
@pytest -m 标记名称 -v
#例
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
'''
命令行输入: pytest -m great -v
'''
创建固定装置/测试夹具
定义:
fixture(夹具)是函数,将在应用它的每个测试函数之前运行。 fixture(夹具)用于向测试提供一些数据,例如数据库连接、要测试的 URL 和某种输入数据。 因此,我们可以将 fixture 函数附加到测试,而不是为每个测试运行相同的代码,它会在执行每个测试之前运行并将数据返回给测试。
格式:
@pytest.fixture
举例:
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
'''
命令行输入: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
==========================
'''
fixture使用的局限性
该方法有其自身的局限性。 测试文件内定义的fixture(夹具)函数仅在测试文件内具有作用域。 我们不能在另一个测试文件中使用该fixture(夹具)。 为了使fixture(夹具)可用于多个测试文件,我们必须在名为 conftest.py 的文件中定义fixture(夹具)函数。 conftest.py 在下一章解释。
允许从多个文件访问装置
- 新建conftest.py文件。
- 将需要跨文件使用的fixture 函数写在此文件中。
- 将fixture 函数名称作为参数传入函数即可使用。
测试参数化
测试的参数化是为了针对多组输入运行测试。 我们可以通过使用以下标记来做到这一点 。
@pytest.mark.parametrize
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
'''
命令行执行命令: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
==============================
'''
Xfail/Skip测试
运用场景:
- 由于某些原因,测试在一段时间内不相关。
- 一项新功能正在实施中,我们已经为该功能添加了测试。在这些情况下,我们可以选择让测试失败或跳过测试。
xfail测试:
xfail会执行测试,但不会被视为部分失败或通过测试。 即使测试失败,也不会打印这些测试的详细信息(记住 pytest 通常会打印失败的测试详细信息)。 我们可以使用以下标记进行 xfail 测试 。
@pytest.mark.xfail
skip测试:
skip跳过测试意味着测试不会被执行,可以使用以下标记跳过测试。
@pytest.mark.skip
举例:
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 文件名称.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次失败后停止测试
运用场景:
在实际场景中,一旦新版本的代码准备好部署,它首先会部署到预生产/暂存环境中。 然后在其上运行测试套件。
只有在测试套件通过时,代码才有资格部署到生产环境。 如果有测试失败,无论是一个还是多个,都不是生产环境就绪的代码。
因此,如果我们想在 n 次测试失败后立即停止测试套件的执行怎么办? 这可以在 pytest 中使用 maxfail 完成。
在 n 次测试失败后立即停止执行测试套件的语法如下 :
pytest 文件名称.py -v --maxfail 1 (1表示只要在测试中有一个用例失败则立即停止执行)
并行测试
运用场景:
默认情况下,pytest 按顺序运行测试。 在真实场景中,一个测试套件会有很多测试文件,每个文件会有一堆测试。 这将导致大量的执行时间。 为了克服这个问题,pytest 为我们提供了一个并行运行测试的选项。
安装 pytest-xdist 插件:
pip install pytest-xdist
运行语法:
pytest -n 3 (使用多个 worker 运行测试,这里是 3 个)
注意:
当只有几个测试要运行时,我们不会有太大的时间差异。 但是,当测试套件很大时,这很重要。
生成XML测试结果
运用场景:
我们可以在 xml 文件中生成测试执行的详细信息。 这个 xml 文件主要在我们有一个仪表板来投影测试结果的情况下有用。 在这种情况下,可以解析 xml 以获取执行的详细信息。
运行语法:
pytest 文件名称.py -v --junitxml="result.xml"
Pytest总结
- 根据被测试的功能/模块创建不同的测试文件。
- 为测试文件和方法提供有意义的名称。
- 有足够的标记,可以根据各种标准对测试进行分组。
- 根据需要使用夹具(fixture)。