我不谈论Parameterizing a fixture功能,该功能允许灯具多次运行以获得硬编码参数。
我有很多测试遵循以下模式:
httpcode = 401 # this is different per call
message = 'some message' # this is different per call
url = 'some url' # this is different per call
mock_req = mock.MagicMock(spec_set=urllib2.Request)
with mock.patch('package.module.urllib2.urlopen', autospec=True) as mock_urlopen, \
mock.patch('package.module.urllib2.Request', autospec=True) as mock_request:
mock_request.return_value = mock_req
mock_urlopen.side_effect = urllib2.HTTPError(url, httpcode, message, {}, None)
connection = MyClass()
with pytest.raises(MyException):
connection.some_function() # this changes
基本上,我有一个类是API客户端,并且包含自定义的,有意义的异常,它们将urllib2错误包装在特定于API的内容中。所以,我有这个模式 - 修补一些方法,并在其中一个上设置副作用。我在十几个不同的测试中使用它,唯一的区别是side_effect的部分使用的三个变量,以及我调用的MyClass()的方法。
有没有办法让它成为pytest fixture并传入这些变量?
答案 0 :(得分:17)
您可以使用间接夹具参数化 http://pytest.org/latest/example/parametrize.html#deferring-the-setup-of-parametrized-resources
@pytest.fixture()
def your_fixture(request):
httpcode, message, url = request.param
mock_req = mock.MagicMock(spec_set=urllib2.Request)
with mock.patch('package.module.urllib2.urlopen', autospec=True) as mock_urlopen, \
mock.patch('package.module.urllib2.Request', autospec=True) as mock_request:
mock_request.return_value = mock_req
mock_urlopen.side_effect = urllib2.HTTPError(url, httpcode, message, {}, None)
connection = MyClass()
with pytest.raises(MyException):
connection.some_function() # this changes
@pytest.mark.parametrize('your_fixture', [
(403, 'some message', 'some url')
], indirect=True)
def test(your_fixture):
...
并且your_fixture将在测试之前使用所需的参数
运行答案 1 :(得分:6)
自从发布我的问题以来,我已经对此进行了更多的研究,我能想到的最好的是:
固定装置不会这样工作。只需使用常规功能,即:
def my_fixture(httpcode, message, url):
mock_req = mock.MagicMock(spec_set=urllib2.Request)
with mock.patch('package.module.urllib2.urlopen', autospec=True) as mock_urlopen, \
mock.patch('package.module.urllib2.Request', autospec=True) as mock_request:
mock_request.return_value = mock_req
mock_urlopen.side_effect = urllib2.HTTPError(url, httpcode, message, {}, None)
connection = MyClass()
return (connection, mock_request, mock_urlopen)
def test_something():
connection, mock_req, mock_urlopen = my_fixture(401, 'some message', 'some url')
with pytest.raises(MyException):
connection.some_function() # this changes
答案 2 :(得分:1)
我知道这是旧的,但也许有助于再次绊倒的人
@pytest.fixture
def data_patcher(request):
def get_output_test_data(filename, as_of_date=None):
# a bunch of stuff to configure output
return output
def teardown():
pass
request.addfinalizer(teardown)
return get_output_test_data
然后,在函数内部:
with patch('function to patch', new=data_patcher):
答案 3 :(得分:0)
如何将参数传递到夹具中?
暂时解开这个主意:您实际上是在寻求一种夹具,该夹具是对参数做出反应的函数。因此,返回一个对参数起作用的函数:
@pytest.fixture
def get_named_service():
def _get_named_service(name):
result = do_something_with_name(name)
return result
return _get_named_service
然后,在测试中,为函数提供参数:
def test_stuff(get_named_service):
awesome_service = get_named_service('awesome')
terrible_service = get_named_service('terrible')
# Now you can do stuff with both services.
这被记录为工厂模式:
https://docs.pytest.org/en/latest/fixture.html#factories-as-fixtures
正如OP所发现的,这只是一个函数,但其优点是位于conftest
内,所有其他公用程序和设置/拆卸代码均位于其中;加上自我记录测试的依赖性。