初始设置
假设您有一个带有conftest.py 的简化项目,其中包含以下代码:
import pytest
def pytest_addoption(parser):
parser.addoption('--foo', action='store', dest='foo', default='bar',
help='--foo should be always bar!')
@pytest.fixture
def foo(request):
fooval = request.config.getoption('foo')
if fooval != 'bar':
raise ValueError('expected foo to be "bar"; "{}" provided'.format(fooval))
它添加了一个新的命令行参数--foo 和一个夹具foo 返回传递的参数,或者bar 如果未指定。如果除了bar 之外的任何其他内容通过--foo 传递,则夹具会引发ValueError。
你照常使用夹具,例如
def test_something(foo):
assert foo == 'bar'
现在让我们测试一下这个夹具。
准备工作
在这个例子中,我们需要先做一些简单的重构。将夹具和相关代码移动到某个名为 conftest.py 以外的文件,例如 my_plugin.py:
# my_plugin.py
import pytest
def pytest_addoption(parser):
parser.addoption('--foo', action='store', dest='foo', default='bar',
help='--foo should be always bar!')
@pytest.fixture
def foo(request):
fooval = request.config.getoption('foo')
if fooval != 'bar':
raise ValueError('expected foo to be "bar"; "{}" provided'.format(fooval))
在conftest.py 中,确保加载了新插件:
# conftest.py
pytest_plugins = ['my_plugin']
运行现有的测试套件以确保我们没有破坏任何东西,所有测试仍应通过。
激活pytester
pytest 提供了一个额外的插件来编写插件测试,称为pytester。默认情况下未激活它,因此您应该手动执行此操作。在conftest.py 中,使用pytester 扩展插件列表:
# conftest.py
pytest_plugins = ['my_plugin', 'pytester']
编写测试
一旦pytester 处于活动状态,您将获得一个名为testdir 的新设备。它可以从代码生成和运行pytest 测试套件。这是我们的第一个测试的样子:
# test_foo_fixture.py
def test_all_ok(testdir):
testdata = '''
def test_sample(foo):
assert True
'''
testconftest = '''
pytest_plugins = ['my_plugin']
'''
testdir.makeconftest(testconftest)
testdir.makepyfile(testdata)
result = testdir.runpytest()
result.assert_outcomes(passed=1)
这里发生的事情应该很明显:我们将测试代码作为字符串提供,testdir 将在某个临时目录中从中生成一个pytest 项目。为了确保我们的foo 夹具在生成的测试项目中可用,我们在生成的conftest 中传递它,就像我们在真实项目中所做的那样。 testdir.runpytest() 开始测试运行,产生我们可以检查的结果。
让我们添加另一个测试来检查foo 是否会引发ValueError:
def test_foo_valueerror_raised(testdir):
testdata = '''
def test_sample(foo):
assert True
'''
testconftest = '''
pytest_plugins = ['my_plugin']
'''
testdir.makeconftest(testconftest)
testdir.makepyfile(testdata)
result = testdir.runpytest('--foo', 'baz')
result.assert_outcomes(error=1)
result.stdout.fnmatch_lines([
'*ValueError: expected foo to be "bar"; "baz" provided'
])
这里我们使用--foo baz 执行生成的测试,然后验证一个测试是否以错误结束并且错误输出包含预期的错误消息。