简体   繁体   English

Pytest 使用参数化夹具 VS。 pytest.mark.parametrize

[英]Pytest Using Parametized Fixture VS. pytest.mark.parametrize

I'm writing some unit tests using Pytest and came across two ways to parameterize test inputs.我正在使用 Pytest 编写一些单元测试,并遇到了两种参数化测试输入的方法。 One is using parametereized fixtures and the other is using the pytest.mark.parametrize method.一种是使用参数化装置,另一种是使用pytest.mark.parametrize方法。

The two examples I have are:我的两个例子是:

# method 1
def tokens():
    yield from ["+", "*", "?"]

@pytest.mark.parametrize("token", tokens())
def test_stuff(token):
    assert stuff

and

# method 2
@pytest.fixture(params=["+", "*", "?"])
def token(request):
    return request.param

def test_stuff(token):
    assert stuff

Both have different advantages and disadvantages from what I can tell:据我所知,两者都有不同的优点和缺点:

Method 1方法一

Advantages好处

  • Supports multiple parameters支持多个参数
  • Supports lazy evaluation支持惰性求值

Disadvantages缺点

  • More boilerplate code when used for multiple test methods用于多种测试方法时更多样板代码
  • requires explicit parameter mapping for every method used, even if parameters are the same name需要为使用的每个方法显式参数映射,即使参数名称相同

method 2方法二

Advantages好处

  • Less Boiler Plate code减少锅炉板代码

Disadvantages缺点

  • Only allows single parameter to be passed to unit test只允许将单个参数传递给单元测试

I'm still new to PyTest so maybe there is a way around the disadvantages that I listed above for each method but given those I have been having a hard time trying to decide which one to use.我还是 PyTest 的新手,所以也许有一种方法可以解决我上面为每种方法列出的缺点,但考虑到这些缺点,我一直很难决定使用哪种方法。 I would guess that the intended way to do what I am trying to do is to use @pytest.mark.parametrize but when passing only a single parameter having less boilerplate code by using a fixture seems like a big advantage.我猜想我想要做的事情的预期方法是使用@pytest.mark.parametrize但是当通过使用夹具只传递具有较少样板代码的单个参数时似乎是一个很大的优势。 Can anyone tell me a reason not to do it this way or is this a perfectly valid use case?谁能告诉我不这样做的理由,或者这是一个完全有效的用例吗?

As pk786 mentions in his comment, you should use a fixture "...if you have something to set up and teardown for the test or using (the) same dataset for multiple tests then use fixture".正如pk786在他的评论中提到的,你应该使用一个夹具“......如果你有一些东西要为测试设置和拆卸,或者使用()相同的数据集进行多个测试然后使用夹具”。

For example, you may want to load several datasets that you test against in different test functions.例如,您可能希望加载在不同测试函数中进行测试的多个数据集。 Using a fixture allows you to only load these datasets once and share them across the test functions.使用夹具允许您只加载一次这些数据集并在测试函数中共享它们。 You can use params argument of @pytest.fixture to load and cache each dataset.您可以使用@pytest.fixture params参数来加载和缓存每个数据集。 Then, the test functions that use those fixtures will run against each loaded dataset.然后,使用这些装置的测试函数将针对每个加载的数据集运行。 In code, this might look something like:在代码中,这可能类似于:

import json

import pytest


test_files = ["test_file1.json", "test_file2.json"]


@pytest.fixture(params=test_files)
def example_data(request):
    with open(request.param, "r") as f:
        data = json.load(f)
    return data


def test_function1(example_data):
    # run test with example data.
    # this test will be run once for each file in the list `test_files` above.
    ...


def test_function2(example_data):
    # run a different test with example data.
    # this test will be run once for each file in the list `test_files` above.
    # this test takes advantage of automatic caching mechanisms of fixtures...
    # ...so that data is not loaded again.
    ...   

Alternatively, as pk786 states, "If you are using a set of data only once, then @pytest.mark.parametrize should be the approach".或者,正如pk786所述,“如果您只使用一组数据一次,那么@pytest.mark.parametrize 应该是方法”。

This statement applies to the example that you provided since you are not performing any setup in the fixture that you need to share across test.此声明适用于您提供的示例,因为您没有在需要跨测试共享的夹具中执行任何设置。 In this case, even if you are using the "tokens" across multiple tests, I would consider decorating each function with @pytest.mark.parameterize since I believe this approach more explicitly states your intent and will be easier to understand for anyone else reading your code.在这种情况下,即使您在多个测试中使用“令牌”,我也会考虑用@pytest.mark.parameterize装饰每个函数,因为我相信这种方法更明确地说明了您的意图,并且对于其他阅读的人来说更容易理解你的代码。 This would look like this:这看起来像这样:

...

def tokens():
    yield from ["+", "*", "?"]


@pytest.mark.parametrize("token", tokens())
def test_stuff(token):
    assert stuff


@pytest.mark.parametrize("token", tokens())
def test_other_stuff("token", tokens())
    assert other_stuff

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

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