假设我有一个函数,它接收一个字符串并返回前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个问题:
baseline
,longer
,even_longer
)以使测试能够运行的“良好实践”方式。@pytest.fixture
def setup_test_data():
baseline = "hello"
longer = "hello world"
even_longer = "hello world!"
return baseline, longer, even_longer
(这是一个愚蠢的例子,但希望足以解释我的问题)。
谢谢!
答案 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