如何测试pytest固定装置本身? [英] How to test the pytest fixture itself?
问题描述
测试pytest固定装置本身的正确方法是什么?请不要将其与在测试中使用夹具混淆.我只想自己测试灯具的正确性.
What is the proper way to test that the pytest fixture itself. Please do not confuse it with using fixture in tests. I want just tests the fixtures correctness by itself.
在测试中尝试调用并执行它们时,我将面临:
When trying to call and execute them inside test I am facing:
Fixture "app" called directly. Fixtures are not meant to be called directly
对此表示感谢.关于此主题的文档没有给我有意义的指导: https://docs.pytest.org/en/latest/deprecations.html#calling-fixtures-direct
Any input on that will be appreciated. Docs on this topic are not giving me meaningful guidance: https://docs.pytest.org/en/latest/deprecations.html#calling-fixtures-directly
测试治具本身的动机就在于我,因为当我们的测试由于治具中的错误而失败时,这在我们的TAP文件中无法正确跟踪,这促使我独自测试治具.
The motivation for testing fixtures itself come to me, because when our test were failing due to bug in fixture this wasn't tracked correctly in our TAP files, what motivated me to test the fixtures stand alone.
推荐答案
pytest
具有 pytester
插件,用于测试pytest
本身和插件;它在不影响当前测试运行的隔离运行中执行测试.示例:
pytest
has a pytester
plugin that was made for the purpose of testing pytest
itself and plugins; it executes tests in an isolated run that doesn't affect the current test run. Example:
# conftest.py
import pytest
pytest_plugins = ['pytester']
@pytest.fixture
def spam(request):
yield request.param
夹具spam
有一个问题,它仅适用于参数化测试.一旦在非参数化测试中要求它,它将产生一个AttributeError
.这意味着我们无法通过这样的常规测试来对其进行测试:
The fixture spam
has an issue that it will only work with parametrized tests; once it is requested in an unparametrized test, it will raise an AttributeError
. This means that we can't test it via a regular test like this:
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
夹具在隔离的测试运行中执行测试:
Instead, we execute the test in an isolated test run using the testdir
fixture which is provided by the pytester
plugin:
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
中设置根路径,例如:
Another handy possibility of loading test code for the tests is the testdir.copy_example
method. Setup the root path in the pytest.ini
, for example:
[pytest]
pytester_example_dir = samples_for_fixture_tests
norecursedirs = samples_for_fixture_tests
现在使用以下内容创建文件samples_for_fixture_tests/test_spam_fixture/test_x.py
:
Now create the file samples_for_fixture_tests/test_spam_fixture/test_x.py
with the contents:
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
的代码相同).上面的测试更改为:
(it's the same code that was passed as string to testdir.makepyfile
before). The above test changes to:
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
标记配置测试数据根:
This way, you don't have to maintain Python code as string in tests and can also reuse existing test modules by running them with pytester
. You can also configure test data roots via the pytester_example_path
mark:
@pytest.mark.pytester_example_path('fizz')
def test_fizz(testdir):
testdir.copy_example('buzz.txt')
将查找相对于项目根目录的文件fizz/buzz.txt
.
will look for the file fizz/buzz.txt
relative to the project root dir.
有关更多示例,请务必查看测试插件在pytest
文档中;此外,对于问题 Testdir
代码,可悲的是pytest
并没有为此提供广泛的文档,但是代码几乎是自我记录的.
For more examples, definitely check out the section Testing plugins in pytest
docs; also, you may find my other answer to the question How can I test if a pytest fixture raises an exception? helpful as it contains yet another working example to the topic. I have also found it very helpful to study the Testdir
code directly as sadly pytest
doesn't provide an extensive docs for it, but the code is pretty much self-documenting.
这篇关于如何测试pytest固定装置本身?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!