如何在同一测试中实现pytest fixture和参数化参数作为参数



我想为一个名为Graph的类创建一个测试。我创建了一个名为my_graph的fixture,该fixture只创建一个Graph实例。现在我想创建一个测试,它接受fixture和参数化参数,这些参数包含输入和预期输出的列表。

以下是我在下面尝试的内容,但我一直发现vertex固定装置找不到。

@pytest.fixture
def my_graph() -> adjacency_list.Graph:
g = adjacency_list.Graph()    
return g
@pytest.mark.parametrize("my_graph, vertex, expected",
[('A', ['A']), (1, [1])])
def test_add_vertex(my_graph: adjacency_list.Graph, vertex: Union[str, int], expected: List[Union[str, int]]):
my_graph.add_vertex(vertex)
assert all([a == b for a, b in zip(my_graph.get_vertices(), expected))

错误在于将my_graph夹具包含在.parametrize(arg_names,...)中。

由于my_graph已经是一个fixture,并且您似乎正在以相同的方式为所有测试创建一个Graph实例,因此不需要对其进行参数化。只需将其声明为测试函数的参数,pytest就会找到您的fixture:

# Remove "my_graph" from here ---▼
@pytest.mark.parametrize("vertex, expected", [("A", ["A"]), (1, [1])])
def test_add_vertex(my_graph: Graph, vertex: Union[str, int], expected: List[Union[str, int]]):
...

我想您对@pytest.mark.parametrize示例感到困惑,该示例显示测试的所有输入都是参数化的。不一定非得那样只有那些将具有多个可能值的输入才应包含在.parametrize声明中。对于其他fixture(@pytest.fixture(,只需在测试函数参数中按原样声明即可。

还要注意,parametrize的签名期望argnames的数量和argvalues的数量应该匹配:

@pytest.mark.parametrize("input_a, input_b, input_c", [
("param_a1", "param_b1", "param_c1"),
("param_a2", "param_b2", "param_c2"),
("param_a3", "param_b3", "param_c3"),
...    
])

这里有3个参数化的输入,所以列表应该是3项元组。当参数化测试时,这是一个常见的问题,这将产生诸如"错误"之类的错误夹具未找到";或">必须等于值的数目";。

因此,例如,如果您需要根据参数化的vertexexpected以不同的方式实例化Graph对象,那么您还需要在元组的.parametrize列表中包括实例化的Graph对象:

class Graph:
def __init__(self, name: str):
self._name = name
self._vertices = []
...
@pytest.mark.parametrize(
"input_graph, vertex, expected",
[
(Graph("Graph A"), "A", ["A"]),
(Graph("Graph 1"), 1, [1]),
],
)
def test_add_vertex(input_graph, vertex: Union[str, int], expected: List[Union[str, int]]):
input_graph.add_vertex(vertex)
assert all([a == b for a, b in zip(input_graph.get_vertices(), expected)])

这里,parametrize声明了一个不同名称的input_graph,而不是使用my_graph固定装置,并且每组测试输入实例化一个Graph对象。重命名主要是为了避免与my_graph固定装置混淆。

最新更新