如何测试pytest固定装置本身? [英] How to test the pytest fixture itself?

查看:182
本文介绍了如何测试pytest固定装置本身?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

测试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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆