使用案例:在pytest
测试套件中,我有一个@fixture
,如果缺少配置的命令行选项,则会引发异常。我使用xfail
编写了一个测试夹具:
import pytest
from <module> import <exception>
@pytest.mark.xfail(raises=<exception>)
def test_fixture_with_missing_options_raises_exception(rc_visard):
pass
然而,运行测试后的输出并未将测试声明为已通过,而是“xfailed”:
============================== 1 xfailed in 0.15 seconds ========================
除此之外,我无法测试fixture
是否会针对特定缺失的命令行选项引发异常。
有更好的方法吗?我可以以某种方式模拟pytest
命令行选项,我不需要通过pytest --<commandline-option-a> <test-file-name>::<test-name>
调用特定测试。
答案 0 :(得分:1)
假设您有一个包含以下代码的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))
它添加了一个新的命令行arg --foo
和一个fixture foo
返回传递的arg,如果没有指定则返回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
执行生成的测试,然后验证一个测试是否以错误结束并且错误输出包含预期的错误消息。