如何测试 pytest fixture 本身?
How to test the pytest fixture itself?
测试 pytest fixture 本身的正确方法是什么。请不要将它与在测试中使用夹具混淆。我只想自己测试固定装置的正确性。
当我尝试在测试中调用并执行它们时,我面临:
Fixture "app" called directly. Fixtures are not meant to be called directly
如有任何意见,我们将不胜感激。关于这个主题的文档没有给我有意义的指导:https://docs.pytest.org/en/latest/deprecations.html#calling-fixtures-directly
测试装置本身的动力来自于我,因为当我们的测试由于装置中的错误而失败时,我们的 TAP 文件中没有正确跟踪,是什么促使我单独测试装置。
pytest
有一个 pytester
插件,是为了测试 pytest
本身和插件而制作的;它在不影响当前测试 运行 的隔离 运行 中执行测试。示例:
# conftest.py
import pytest
pytest_plugins = ['pytester']
@pytest.fixture
def spam(request):
yield request.param
fixture spam
有一个问题,它只能用于参数化测试;一旦在未参数化测试中被请求,它将引发 AttributeError
。这意味着我们无法通过这样的常规测试来测试它:
def test_spam_no_params(spam):
# too late to verify anything - spam already raised in test setup!
# In fact, the body of this test won't be executed at all.
pass
相反,我们使用 pytester
插件提供的 testdir
夹具在隔离测试 运行 中执行测试:
import pathlib
import pytest
# an example on how to load the code from the actual test suite
@pytest.fixture
def read_conftest(request):
return pathlib.Path(request.config.rootdir, 'conftest.py').read_text()
def test_spam_fixture(testdir, read_conftest):
# you can create a test suite by providing file contents in different ways, e.g.
testdir.makeconftest(read_conftest)
testdir.makepyfile(
"""
import pytest
@pytest.mark.parametrize('spam', ('eggs', 'bacon'), indirect=True)
def test_spam_parametrized(spam):
assert spam in ['eggs', 'bacon']
def test_spam_no_params(spam):
assert True
""")
result = testdir.runpytest()
# we should have two passed tests and one failed (unarametrized one)
result.assert_outcomes(passed=3, error=1)
# if we have to, we can analyze the output made by pytest
assert "AttributeError: 'SubRequest' object has no attribute 'param'" in ' '.join(result.outlines)
另一种为测试加载测试代码的便捷方法是 testdir.copy_example
方法。在pytest.ini
中设置根路径,例如:
[pytest]
pytester_example_dir = samples_for_fixture_tests
norecursedirs = samples_for_fixture_tests
现在创建文件 samples_for_fixture_tests/test_spam_fixture/test_x.py
,内容如下:
import pytest
@pytest.mark.parametrize('spam', ('eggs', 'bacon'), indirect=True)
def test_spam_parametrized(spam):
assert spam in ['eggs', 'bacon']
def test_spam_no_params(spam):
assert True
(与之前作为字符串传递给 testdir.makepyfile
的代码相同)。上述测试改为:
def test_spam_fixture(testdir, read_conftest):
testdir.makeconftest(read_conftest)
# pytest will now copy everything from samples_for_fixture_tests/test_spam_fixture
testdir.copy_example()
testdir.runpytest().assert_outcomes(passed=3, error=1)
这样,您就不必在测试中将 Python 代码维护为字符串,并且还可以通过 运行 将它们与 pytester
结合来重用现有的测试模块。也可以通过pytester_example_path
标记配置测试数据根:
@pytest.mark.pytester_example_path('fizz')
def test_fizz(testdir):
testdir.copy_example('buzz.txt')
将查找相对于项目根目录的文件 fizz/buzz.txt
。
有关更多示例,请务必直接查看 Testing plugins in pytest
docs; also, you may find to the question helpful as it contains yet another working example to the topic. I have also found it very helpful to study the Testdir
code 部分,遗憾的是 pytest
没有为其提供详尽的文档,但代码非常多 self-documenting。
测试 pytest fixture 本身的正确方法是什么。请不要将它与在测试中使用夹具混淆。我只想自己测试固定装置的正确性。
当我尝试在测试中调用并执行它们时,我面临:
Fixture "app" called directly. Fixtures are not meant to be called directly
如有任何意见,我们将不胜感激。关于这个主题的文档没有给我有意义的指导:https://docs.pytest.org/en/latest/deprecations.html#calling-fixtures-directly
测试装置本身的动力来自于我,因为当我们的测试由于装置中的错误而失败时,我们的 TAP 文件中没有正确跟踪,是什么促使我单独测试装置。
pytest
有一个 pytester
插件,是为了测试 pytest
本身和插件而制作的;它在不影响当前测试 运行 的隔离 运行 中执行测试。示例:
# conftest.py
import pytest
pytest_plugins = ['pytester']
@pytest.fixture
def spam(request):
yield request.param
fixture spam
有一个问题,它只能用于参数化测试;一旦在未参数化测试中被请求,它将引发 AttributeError
。这意味着我们无法通过这样的常规测试来测试它:
def test_spam_no_params(spam):
# too late to verify anything - spam already raised in test setup!
# In fact, the body of this test won't be executed at all.
pass
相反,我们使用 pytester
插件提供的 testdir
夹具在隔离测试 运行 中执行测试:
import pathlib
import pytest
# an example on how to load the code from the actual test suite
@pytest.fixture
def read_conftest(request):
return pathlib.Path(request.config.rootdir, 'conftest.py').read_text()
def test_spam_fixture(testdir, read_conftest):
# you can create a test suite by providing file contents in different ways, e.g.
testdir.makeconftest(read_conftest)
testdir.makepyfile(
"""
import pytest
@pytest.mark.parametrize('spam', ('eggs', 'bacon'), indirect=True)
def test_spam_parametrized(spam):
assert spam in ['eggs', 'bacon']
def test_spam_no_params(spam):
assert True
""")
result = testdir.runpytest()
# we should have two passed tests and one failed (unarametrized one)
result.assert_outcomes(passed=3, error=1)
# if we have to, we can analyze the output made by pytest
assert "AttributeError: 'SubRequest' object has no attribute 'param'" in ' '.join(result.outlines)
另一种为测试加载测试代码的便捷方法是 testdir.copy_example
方法。在pytest.ini
中设置根路径,例如:
[pytest]
pytester_example_dir = samples_for_fixture_tests
norecursedirs = samples_for_fixture_tests
现在创建文件 samples_for_fixture_tests/test_spam_fixture/test_x.py
,内容如下:
import pytest
@pytest.mark.parametrize('spam', ('eggs', 'bacon'), indirect=True)
def test_spam_parametrized(spam):
assert spam in ['eggs', 'bacon']
def test_spam_no_params(spam):
assert True
(与之前作为字符串传递给 testdir.makepyfile
的代码相同)。上述测试改为:
def test_spam_fixture(testdir, read_conftest):
testdir.makeconftest(read_conftest)
# pytest will now copy everything from samples_for_fixture_tests/test_spam_fixture
testdir.copy_example()
testdir.runpytest().assert_outcomes(passed=3, error=1)
这样,您就不必在测试中将 Python 代码维护为字符串,并且还可以通过 运行 将它们与 pytester
结合来重用现有的测试模块。也可以通过pytester_example_path
标记配置测试数据根:
@pytest.mark.pytester_example_path('fizz')
def test_fizz(testdir):
testdir.copy_example('buzz.txt')
将查找相对于项目根目录的文件 fizz/buzz.txt
。
有关更多示例,请务必直接查看 Testing plugins in pytest
docs; also, you may find Testdir
code 部分,遗憾的是 pytest
没有为其提供详尽的文档,但代码非常多 self-documenting。