Pytest框架使用教程

发布时间 2023-11-14 17:53:38作者: 刘家小仙女

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 在下一章解释。

允许从多个文件访问装置

  1. 新建conftest.py文件。
  2. 将需要跨文件使用的fixture 函数写在此文件中。
  3. 将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)。