简体   繁体   English

使用 py.test 数据驱动测试进行设置和拆卸

[英]setup and teardown with py.test data driven testing

I have a lot of tests that basically do the same actions but with different data, so I wanted to implement them using pytest, I managed to do it in a typical junit way like this:我有很多测试基本上执行相同的操作但使用不同的数据,所以我想使用 pytest 来实现它们,我设法以典型的 junit 方式执行它,如下所示:

import pytest
import random

d = {1: 'Hi',2: 'How',3: 'Are',4:'You ?'}

def setup_function(function):
    print("setUp",flush=True)

def teardown_function(functions):
    print("tearDown",flush=True)

@pytest.mark.parametrize("test_input", [1,2,3,4])
def test_one(test_input):
    print("Test with data " + str(test_input))
    print(d[test_input])
    assert True

Which gives me the following output这给了我以下输出

C:\\Temp>pytest test_prueba.py -s C:\\Temp>pytest test_prueba.py -s

============================= test session starts ============================= platform win32 -- Python 3.6.5, pytest-3.5.0, py-1.5.3, pluggy-0.6.0 rootdir: C:\\Temp, inifile: collected 4 items ============================ 测试会话开始 ================== ============ 平台 win32 -- Python 3.6.5, pytest-3.5.0, py-1.5.3, pluggy-0.6.0 rootdir: C:\\Temp, inifile: 收集 4 项

test_prueba.py test_prueba.py

setUp设置

Test with data 1测试数据 1

Hi

.tearDown .tearDown

setUp设置

Test with data 2用数据 2 测试

How如何

.tearDown .tearDown

setUp设置

Test with data 3用数据 3 测试

Are

.tearDown .tearDown

setUp设置

Test with data 4用数据 4 测试

You ?你?

.tearDown .tearDown

========================== 4 passed in 0.03 seconds =========================== ========================== 4 在 0.03 秒内通过 ================== ========

The problem now is that I would perform some actions also in the setup and teardown that I need to access to the test_input value现在的问题是我也会在设置和拆卸中执行一些我需要访问 test_input 值的操作

Is there any elegant solution for this ?对此有什么优雅的解决方案吗? Maybe to achieve this I should use the parametrization or the setup teardown in a different way ?也许要实现这一点,我应该以不同的方式使用参数化或设置拆卸? If that the case can someone put an example of data driven testing with setup and teardown parametrized ?如果是这种情况,有人可以举一个设置和拆卸参数化的数据驱动测试示例吗?

Thanks !!!谢谢!!!

parameterize on a test is more for just specifying raw inputs and expected outputs.测试中的parameterize更多地用于指定原始输入和预期输出。 If you need access to the parameter in the setup, then it's more part of a fixture than a test.如果您需要访问设置中的参数,那么它更像是夹具的一部分而不是测试。

So you might like to try:所以你可能想尝试:

import pytest

d = {"good": "SUCCESS", "bad": "FAIL"}

def thing_that_uses_param(param):
    print("param is", repr(param))
    yield d.get(param)
    print("test done")

@pytest.fixture(params=["good", "bad", "error"])
def parameterized_fixture(request):
    param = request.param
    yield from thing_that_uses_param(param)

def test_one(parameterized_fixture):
    assert parameterized_fixture.lower() == "success"

Which outputs:哪些输出:

============================= test session starts =============================
platform win32 -- Python 3.5.1, pytest-3.4.0, py-1.5.2, pluggy-0.6.0 -- c:\Users\User\AppData\Local\Programs\Python\Python35-32\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\User\Documents\python, inifile:

collecting ... collected 3 items

a.py::test_one[good] PASSED                                              [ 33%]
a.py::test_one[bad] FAILED                                               [ 66%]
a.py::test_one[error] FAILED                                             [100%]

================================== FAILURES ===================================
________________________________ test_one[bad] ________________________________

parameterized_fixture = 'FAIL'

    def test_one(parameterized_fixture):
>       assert parameterized_fixture.lower() == "success"
E       AssertionError: assert 'fail' == 'success'
E         - fail
E         + success

a.py:28: AssertionError
---------------------------- Captured stdout setup ----------------------------
param is 'bad'
-------------------------- Captured stdout teardown ---------------------------
test done
_______________________________ test_one[error] _______________________________

parameterized_fixture = None

    def test_one(parameterized_fixture):
>       assert parameterized_fixture.lower() == "success"
E       AttributeError: 'NoneType' object has no attribute 'lower'

a.py:28: AttributeError
---------------------------- Captured stdout setup ----------------------------
param is 'error'
-------------------------- Captured stdout teardown ---------------------------
test done
===================== 2 failed, 1 passed in 0.08 seconds ======================

However, that requires that you create a parameterized fixture for each set of parameters you might want to use with a fixture.但是,这要求您为可能要与夹具一起使用的每组参数创建一个参数化夹具。

You could alternatively mix and match the parameterized mark and a fixture that reads those params, but that requires the test to uses specific names for the parameters.您也可以混合和匹配参数化标记和读取这些参数的夹具,但这需要测试使用参数的特定名称。 It will also need to make sure such names are unique so it won't conflict with any other fixtures trying to do the same thing.它还需要确保这样的名称是唯一的,这样它就不会与任何其他试图做同样事情的装置发生冲突。 For instance:例如:

import pytest

d = {"good": "SUCCESS", "bad": "FAIL"}

def thing_that_uses_param(param):
    print("param is", repr(param))
    yield d.get(param)
    print("test done")

@pytest.fixture
def my_fixture(request):
    if "my_fixture_param" not in request.funcargnames:
        raise ValueError("could use a default instead here...")
    param = request.getfuncargvalue("my_fixture_param")
    yield from thing_that_uses_param(param)

@pytest.mark.parametrize("my_fixture_param", ["good", "bad", "error"])
def test_two(my_fixture, my_fixture_param):
    assert my_fixture.lower() == "success"

Which outputs:哪些输出:

============================= test session starts =============================
platform win32 -- Python 3.5.1, pytest-3.4.0, py-1.5.2, pluggy-0.6.0 -- c:\Users\User\AppData\Local\Programs\Python\Python35-32\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\User\Documents\python, inifile:
collecting ... collected 3 items

a.py::test_two[good] PASSED                                              [ 33%]
a.py::test_two[bad] FAILED                                               [ 66%]
a.py::test_two[error] FAILED                                             [100%]

================================== FAILURES ===================================
________________________________ test_two[bad] ________________________________

my_fixture = 'FAIL', my_fixture_param = 'bad'

    @pytest.mark.parametrize("my_fixture_param", ["good", "bad", "error"])
    def test_two(my_fixture, my_fixture_param):
>       assert my_fixture.lower() == "success"
E       AssertionError: assert 'fail' == 'success'
E         - fail
E         + success

a.py:25: AssertionError
---------------------------- Captured stdout setup ----------------------------
param is 'bad'
-------------------------- Captured stdout teardown ---------------------------
test done
_______________________________ test_two[error] _______________________________

my_fixture = None, my_fixture_param = 'error'

    @pytest.mark.parametrize("my_fixture_param", ["good", "bad", "error"])
    def test_two(my_fixture, my_fixture_param):
>       assert my_fixture.lower() == "success"
E       AttributeError: 'NoneType' object has no attribute 'lower'

a.py:25: AttributeError
---------------------------- Captured stdout setup ----------------------------
param is 'error'
-------------------------- Captured stdout teardown ---------------------------
test done
===================== 2 failed, 1 passed in 0.08 seconds ======================

I think that what you are looking for is yield fixtures, you can make an auto_use fixture the run something before every test and after and you can access all the test metadata (marks, parameters and etc) you can read it here我认为您正在寻找的是 yield 固定装置,您可以使 auto_use 固定装置在每次测试之前和之后运行某些内容,并且您可以访问所有测试元数据(标记、参数等),您可以在此处阅读

and the access to parameters is via function argument called request并且对参数的访问是通过称为请求的函数参数

IMO, set_up and tear_down should not access test_input values. IMO、set_up 和 tear_down 不应访问 test_input 值。 If you want it to be that way, then probably there is some problem in your test logic.如果您希望这样,那么您的测试逻辑可能存在一些问题。

set_up and tear_down must be independent of values used by test. set_up 和 tear_down 必须独立于测试使用的值。 However, you may use another fixture to get the task done.但是,您可以使用另一个夹具来完成任务。

I have a lot of tests that basically do the same actions but with different data我有很多测试基本上执行相同的操作但使用不同的数据

In addition to Dunes' answer relying solely on pytest, this part of your question makes me think that pytest-cases could be useful to you, too.除了Dunes 的回答完全依赖于 pytest 之外,您问题的这一部分让我认为pytest-cases也可能对您有用。 Especially if some test data should be parametrized while other do not.特别是如果一些测试数据应该被参数化而另一些则没有。

See this other post for an example, and also the documentation of course.有关示例,请参阅一篇文章,当然还有文档 I'm the author by the way ;)顺便说一下,我是作者;)

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

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