简体   繁体   English

如何在同一个测试中将 pytest 固定装置和参数化参数实现为参数?

[英]How to implement pytest fixture and parametrized arguments as arguments on the same test?

I want to create a test for a class called Graph .我想为一个名为Graph的类创建一个测试。 I've created a fixture called my_graph that just creates a Graph instance.我创建了一个名为my_graph的夹具,它只是创建了一个Graph实例。 Now I want to create a test that accepts the fixture and parametrized arguments that contain a list of inputs and expected outputs.现在我想创建一个测试,它接受包含输入和预期输出列表的夹具和参数化参数。

Here is what I've tried below but I keep getting that the vertex fixture is not found.这是我在下面尝试过的,但我一直发现找不到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))

The mistake is including the my_graph fixture in the .parametrize(arg_names,...) .错误是在.parametrize(arg_names,...)包含my_graph夹具。

Since my_graph is already a fixture, and you seem to be creating a Graph instance in the same way for all the tests, you don't need to parametrize it.由于my_graph已经是一个装置,并且您似乎正在以相同的方式为所有测试创建一个Graph实例,因此您不需要对其进行参数化。 Just declare it as a parameter of the test function and pytest will find your fixture:只需将其声明为测试函数的参数,pytest 就会找到您的夹具:

# 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]]):
    ...

I think you got confused from the @pytest.mark.parametrize example, wherein it shows that all inputs to the test are parametrized.我认为您对@pytest.mark.parametrize示例感到困惑,其中显示测试的所有输入都已参数化。 It doesn't have to be like that.不必如此。 Only those inputs that will have multiple possible values should be included in the .parametrize declaration .只有那些具有多个可能值的输入才包含在.parametrize声明中 For other fixtures ( @pytest.fixture ), just declare them as-is in the test function parameters.对于其他装置( @pytest.fixture ),只需在测试函数参数中按原样声明它们。

Note also that the signature for parametrize expects that the number of argnames and the number of argvalues should match:还要注意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"),
    ...    
])

Here, there are 3 parametrized inputs, so the list should be 3-item tuples.这里有 3 个参数化输入,因此列表应该是 3 项元组。 This is a common gotcha when parametrizing tests, and this will produce errors such as " fixture not found " or " must be equal to the number of values ".这是参数化测试时的常见问题,这会产生诸如“未找到夹具”或“必须等于值的数量”之类的错误。

So, if for example, you need to instantiate the Graph object differently based on the parametrized vertex and expected , then you need to also include the instantiated Graph object in the .parametrize list of tuples:所以,如果例如,你需要实例化Graph基础上,参数化的不同对象vertexexpected ,那么你需要包括实例Graph中的对象.parametrize元组的列表:

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)])

Here, instead of using the my_graph fixture, parametrize declares a differently named input_graph , and each set of test inputs instantiates a Graph object.在这里,不是使用my_graph固定装置, parametrize声明了一个不同名称的input_graph ,并且每组测试输入实例化一个Graph对象。 The renaming is mostly to avoid confusion with your my_graph fixture.重命名主要是为了避免与my_graph夹具混淆。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM