【问题标题】:How to test the pytest fixture itself?如何测试 pytest 夹具本身?
【发布时间】:2019-06-17 12:45:47
【问题描述】:

测试 pytest 夹具本身的正确方法是什么。请不要将其与在测试中使用夹具混淆。我只想自己测试灯具的正确性。

当我尝试在我面临的测试中调用和执行它们时:

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 本身也有睾丸。不确定它是否有帮助,但也许你可以看看fixture 的睾丸:github.com/pytest-dev/pytest/blob/…
  • 使用pytester 插件测试绝对是这里的答案。
  • @hoefling 你能提供一些参考,链接到示例/文档..

标签: python unit-testing pytest fixtures


【解决方案1】:

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

如需更多示例,请务必查看 pytest 文档中的 Testing plugins 部分;此外,您可能会发现 my other answer 对问题 How can I test if a pytest fixture raises an exception? 很有帮助,因为它包含该主题的另一个工作示例。我还发现直接研究 Testdir code 非常有帮助,遗憾的是 pytest 没有提供详尽的文档,但代码几乎是自我记录的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多