在类内部进行参数化

时间:2020-08-05 18:49:42

标签: python pytest

假设我有一个函数,它接收一个字符串并返回前5个字符:

def crop_string(x):
    return x[0:5]

例如:

>>> print(crop_string("hello world"))
hello

现在说我想测试这个功能。测试模块的内容如下:

baseline = "hello"
longer = "hello world"
even_longer = "hello world!"

@pytest.mark.parametrize(
    "input_string, expected_result",
    [
        (baseline, baseline),
        (longer, baseline),
        (even_longer, baseline),
    ],
)
def test_crop_string(input_string, expected_result):
    assert crop_string(input_string) == expected_result

会运行的很好。

现在假设这将是具有更多功能的更大测试模块的一部分。如下所示,将这些测试放在类中似乎有好处:

class TestCropString:

    baseline = "hello"
    longer = "hello world"
    even_longer = "hello world!"

    @pytest.mark.parametrize(
        "input_string, expected_result",
        [
            (baseline, baseline),
            (longer, baseline),
            (even_longer, baseline),
        ],
    )
    def test_crop_string(input_string, expected_result):
        assert crop_string(input_string) == expected_result

这给我一个错误:In test_crop_string: function uses no argument 'input_string'

所以我有2个问题:

  1. 什么是“通过”测试参数(baselinelongereven_longer)以使测试能够运行的“良好实践”方式。
  2. 例如在夹具内部定义这些测试参数是否会有好处?
@pytest.fixture
def setup_test_data():
    baseline = "hello"
    longer = "hello world"
    even_longer = "hello world!"

    return baseline, longer, even_longer

(这是一个愚蠢的例子,但希望足以解释我的问题)。

谢谢!

1 个答案:

答案 0 :(得分:1)

由于装饰器是在加载时评估的,因此不能在其中使用类变量,因为在加载时不知道类。这意味着您必须内联或在类外部定义参数。

通常要做的是在全局函数中定义参数:

def get_params():
    baseline = "hello"
    longer = "hello world"
    even_longer = "hello world!"
    return [
        (baseline, baseline),
        (longer, baseline),
        (even_longer, baseline)
    ]

...
    @pytest.mark.parametrize("input_string, expected_result", get_params())
    def test_crop_string(self, test_data):
        ...

在这种情况下,这至少避免了使用全局变量。

关于装饰器:您也不能在装饰器内部使用固定装置。您可以使用参数化夹具,但是只有在您要在类的几种测试方法中使用相同的参数时,这才有意义:

@pytest.fixture(params=get_params())
def test_data(request):
    return request.param
 
class class TestCropString:

    def test_crop_string(self, test_data):
        assert crop_string(test_data[0]) == test_data[1]

如果要将相同的参数应用于类中的所有测试方法,则可以将mark.paramtrize装饰器放在类上。

@pytest.mark.parametrize("input_string, expected_result", get_params())
class TestCropString:

    def test_crop_string(input_string, expected_result):
        assert crop_string(input_string) == expected_result
相关问题