在 Pytest 中使用 MagicMock 对象时如何检查嵌套函数中的异常?



我有一个函数(myfunc),带有验证输入ac凭据,这些凭据将设置服务以调用func_z

对于某些验证输入,func_z将引发错误,在其他情况下,它将返回一些值字典。我有一个修改func_z输出的outer_func.

我试图这样嘲笑func_z

class XError(Excception):
pass
def myfunc(a, b, c):
x = c.setup_client('x')
try:
x.func_z(a) # Check if x.func_z(a) works proper
except:
raise XError

return b**2

def outer_func(a, b, c):
return myfunc(a, b, c) + 1

在测试函数时,我不得不模拟c凭据。所以我尝试用:

import pytest
from unittest.mock import MagicMock

test_data = ( (('fr', 5), 26), ('de', 7, 50), (('zh', 5), XError) )
SIDE_EFFECTS = {'fr': {'status': 'okay'}, 'de': {'status': 'okay'}, 'zh': XError}
@pytest.mark.parametrize("a, b", test_data)
def mytest(a, b, expected):
mock_creds = MagicMock()
mock_service = MagicMock()
mock_creds.setup_client.return_value = mock_service
mock_service.func_z.return_value = SIDE_EFFECTS[a]

assert outer_func(a, b, mock_creds) == expected

不知何故,XError没有在 pytest 中引发,输出返回('zh', 5)输入的26而不是 XError。

但似乎我没有嘲笑任何东西。

我是否错误地使用了模拟对象中的返回值?

是否可以允许和检查在pytest中使用模拟对象引发的错误或输出?

有问题的测试有两个问题。

  1. 在模拟中返回异常:

    mock_service.func_z.return_value = XError
    

    实际上是一个

    def func_z():
    return XError
    

    当然这不是你想要的。相反,您希望func_z模拟引发错误;为此,您需要使用side_effect

    mock_service.func_z.side_effect = XError
    
  2. 断言异常是从测试函数返回的:outer_func返回异常,而是引发异常,所以

    assert outer_func(a, b, mock_creds) == expected
    

    (('zh', 5), XError)参数将失败,因为outer_func不会返回。

相反,编写两个单独的测试,因为代码可以采用两条不同的路径myfunc;test_happy覆盖路径没有例外,而引发错误的路径由test_xerror覆盖。两个测试(组装mock_service)共有的代码被移出到夹具上。

@pytest.fixture
def mock_creds():
mock_creds = MagicMock()
mock_service = MagicMock()
mock_creds.setup_client.return_value = mock_service
return mock_creds

happy_data = (('fr', 5, 26), ('de', 7, 50))
SIDE_EFFECTS = {'fr': {'status': 'okay'}, 'de': {'status': 'okay'}}
@pytest.mark.parametrize("a, b, expected", happy_data)
def test_happy(mock_creds, a, b, expected):
func_z_return = SIDE_EFFECTS[a]
mock_creds.setup_client.return_value.func_z.return_value = func_z_return
assert outer_func(a, b, mock_creds) == expected

xerror_data = (('zh', 5), )
@pytest.mark.parametrize("a, b", xerror_data)
def test_xerror(mock_creds, a, b):
mock_creds.setup_client.return_value.func_z.side_effect = XError
with pytest.raises(XError):
outer_func(a, b, mock_creds)

请注意如何使用pytest.raises上下文来测试是否在上一次测试中引发XError。如果要测试异常详细信息,可以存储引发的异常并在with块之后进行检查:

with pytest.raises(XError) as excinfo:
outer_func(a, b, mock_creds)
ex = excinfo.value
assert isinstance(ex, XError)  # well, duh
assert ex.message == "An XError message if passed"  # etc.

相关内容

  • 没有找到相关文章

最新更新