为所有 pytest 函数定义输入参数

Define input parameters for all pytest functions

我有一个大型 Python 项目,其中包含许多功能,由单个驱动程序 main.py 使用。驱动程序提供所有功能所需的输入参数。我正在使用 pytest 来测试这些功能。下面给出了此类项目的一个基本示例。在示例中,参数定义为 s, t, x, y, z, a, b, c, j, k.

# main.py
# ----------------------------------------------------------------------------

from funcA import funcA
from funcB import funcB

s = 3.4
t = 8
x = 12.9
y = 51
z = 1.04

a = 456.1
b = 203.09
c = 110.72
j = 2.89
k = 4.5

quantity, average = funcA(s, t, x, y, z)

weight = funcB(a, b, c, j, k, y, z)

print(f'{quantity=}')
print(f'{average=}')
print(f'{weight=}')

# funcA.py
# ----------------------------------------------------------------------------

def funcA(s, t, x, y, z):

    quantity = s + t
    average = (x + y + z) / 3

    return quantity, average

# funcB.py
# ----------------------------------------------------------------------------

def funcB(a, b, c, j, k, y, z):

    pounds = a + b + c
    kilograms = j + k + y + z
    weight = pounds + kilograms

    return weight

示例函数的测试如下所示。测试位于 tests 文件夹中,该文件夹与 main.py 驱动程序位于同一目录中。

# test_funcA.py
# ----------------------------------------------------------------------------

import pytest
from funcA import funcA

def test_funcA():

    s = 3.4
    t = 8
    x = 12.9
    y = 51
    z = 1.04

    quantity, average = funcA(s, t, x, y, z)

    assert quantity == pytest.approx(11.4)
    assert average == pytest.approx(21.64, rel=1e-2)

# test_funcB.py
# ----------------------------------------------------------------------------

import pytest
from funcB import funcB

def test_funcB():

    a = 456.1
    b = 203.09
    c = 110.72
    j = 2.89
    k = 4.5

    y = 51
    z = 1.04

    weight = funcB(a, b, c, j, k, y, z)

    assert weight == pytest.approx(829.34)

对于每个测试,我都必须给出被测函数所需的输入参数。对于具有许多参数和功能的大型项目,这种方法很麻烦。因此,我不想为每个测试重新定义参数,而是想一次定义所有参数并将这些参数传递给所有测试。我怎样才能用 pytest 做到这一点?

方法二

我在 conftest.py 中定义了一个夹具,它位于 tests 文件夹中。这似乎是为所有测试提供全局变量(参数)的 pytest 方式。测试使用夹具获取函数的输入参数。

# conftest.py
# ----------------------------------------------------------------------------

import pytest
from dataclasses import dataclass

@dataclass
class Parameters:

    s = 3.4
    t = 8
    x = 12.9
    y = 51
    z = 1.04

    a = 456.1
    b = 203.09
    c = 110.72
    j = 2.89
    k = 4.5

@pytest.fixture()
def parameters():
    params = Parameters()
    return params

# test_funcA.py
# ----------------------------------------------------------------------------

import pytest
from funcA import funcA

def test_funcA(parameters):

    s = parameters.s
    t = parameters.t
    x = parameters.x
    y = parameters.y
    z = parameters.z

    quantity, average = funcA(s, t, x, y, z)

    assert quantity == pytest.approx(11.4)
    assert average == pytest.approx(21.64, rel=1e-2)

# test_funcB.py
# ----------------------------------------------------------------------------

import pytest
from funcB import funcB

def test_funcB(parameters):

    a = parameters.a
    b = parameters.b
    c = parameters.c
    j = parameters.j
    k = parameters.k
    y = parameters.y
    z = parameters.z

    weight = funcB(a, b, c, j, k, y, z)

    assert weight == pytest.approx(829.34)

这种方法允许我在一个地方定义参数值(在 conftest.py 文件中)。但我仍然必须在每个测试中声明输入参数变量,以便将它们传递给正在测试的函数。还有另一种方法,我不必为每个测试重新定义参数变量吗?我可以只将所需的变量传递给测试吗(参见下面的示例)?

import pytest
from funcA import funcA

def test_funcA(s, t, x, y, z):

    quantity, average = funcA(s, t, x, y, z)

    assert quantity == pytest.approx(11.4)
    assert average == pytest.approx(21.64, rel=1e-2)

如果必须为每个后续测试保留对数据的更改,那么您可以使用模块范围的固定装置在测试之间传递数据以一次解决多个问题。

这是可能的样子:

import pytest

@pytest.fixture(scope="module")
def data():
    a = 11
    b = 22
    c = 33
    d = 44
    yield [a, b, c, d]

def test_a(data):
    assert data[0] == 11
    data[1] = 2222

def test_ab(data):
    assert data[0] == 11
    assert data[1] == 2222

def test_abc(data):
    assert data[0] == 11
    assert data[1] == 2222
    assert data[2] == 33
    data[0] = 1111

def test_abd(data):
    assert data[0] == 1111
    assert data[1] == 2222
    assert data[3] == 44

请注意,测试在下一次测试之前更改数据。由于测试 运行 按字母顺序排列,它们都会通过,因为数据与原始数据集不同。为简单起见,我使用了一个灯具,但您可以使用任意多个灯具。

Copy/paste 将其放入 Python 文件并尝试 运行 将其与 pytest 结合。它之所以有效,是因为数据可以在测试之间更改和传递。


第 2 部分(根据您的代码,针对您要查找的内容。)

import pytest

@pytest.fixture(scope="module")
def s():
    value = 3.4
    yield value

@pytest.fixture(scope="module")
def t():
    value = 8
    yield value

@pytest.fixture(scope="module")
def x():
    value = 12.9
    yield value

@pytest.fixture(scope="module")
def y():
    value = 51
    yield value

@pytest.fixture(scope="module")
def z():
    value = 1.04
    yield value

def funcA(s, t, x, y, z):
    quantity = s + t
    average = (x + y + z) / 3
    return quantity, average

def test_funcA(s, t, x, y, z):
    quantity, average = funcA(s, t, x, y, z)
    assert quantity == pytest.approx(11.4)
    assert average == pytest.approx(21.64, rel=1e-2)