在 pytest 参数化中使用类型错误消息

Geo*_*rge 7 python pytest

我有一个函数,当满足某些条件时会引发 TypeError 。

def myfunc(..args here...):
    ... 
    raise TypeError('Message')
Run Code Online (Sandbox Code Playgroud)

我想使用 pytest parametrize 测试此消息。

但是,因为我正在使用其他参数,所以我也想要这样的设置:

testdata = [
        (..args here..., 'Message'), # Message is the expected output
    ]

    @pytest.mark.parametrize(
        "..args here..., expected_output", testdata)
    def test_myfunc(
       ..args here..., expected_output):

        obs = myfunc()
        assert obs == expected_output
Run Code Online (Sandbox Code Playgroud)

简单地将Message预期输出放入参数化测试数据中,就会导致测试失败。

mar*_*aft 8

以下内容来自此处的 pytest 文档

参数化条件引发

pytest.raises()与装饰器一起使用pytest.mark.parametrize来编写参数化测试,其中一些测试引发异常,而另一些测试则不会。

nullcontext用作的补充可能会有所帮助raises

例如:

from contextlib import nullcontext as does_not_raise

import pytest


@pytest.mark.parametrize(
    "example_input,expectation",
    [
        (3, does_not_raise()),
        (2, does_not_raise()),
        (1, does_not_raise()),
        (0, pytest.raises(ZeroDivisionError)),
    ],
)
def test_division(example_input, expectation):
    """Test how much I know division."""
    with expectation:
        assert (6 / example_input) is not None
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,前三个测试用例应该正常运行,而第四个测试用例应该引发ZeroDivisionError

但这对我来说不太有效......

Pytest 文档中的示例导致我收到错误AttributeError: __enter__

看来我的Pythonnullcontext没有__enter__实现方法。因此我必须像这样创建自己的版本:

class MyNullContext:
    def __enter__(self, *args, **kwargs):
        pass
    def __exit__(self, *args, **kwargs):
        pass
does_not_raise = MyNullContext()
Run Code Online (Sandbox Code Playgroud)

并使用它而不是导入内置的nullcontext. 您可以将其放入一个conftest.py文件中,以便它可用于您的所有测试。


Pio*_*iuk 2

您不能期望消息错误作为 的正常输出myfunc。为此有一个特殊的上下文管理器 - pytest.raises

例如,如果您希望出现一些错误及其消息

def test_raises():
    with pytest.raises(Exception) as excinfo:   
        raise Exception('some info')   
    assert str(excinfo.value) == 'some info'
Run Code Online (Sandbox Code Playgroud)

所以,就你而言,这将是类似的

testdata = [
    (..args here..., 'Message')
]

@pytest.mark.parametrize("..args here..., expected_exception_message", testdata)
    def test_myfunc(..args here..., expected_exception_message):
        with pytest.raises(TypeError) as excinfo: 
            obs = myfunc(..args here...)
        assert str(excinfo.value) == expected_exception_message
Run Code Online (Sandbox Code Playgroud)