我目前正在努力寻找一种模拟多层/嵌套返回值的好方法。换句话说,我想返回一个魔法模拟,然后返回一个魔法模拟,它具有自己的设置返回值。我发现这相对比较麻烦,我正在寻找更优雅和可维护的解决方案。
我试图有效地测试以下代码。 URL返回需要进一步处理的json字符串:
class MyTestCase(TestCase):
@patch('load_json_path.urlopen')
def test_load_json(self, mock_urlopen):
### trying to simplify all of this
# third nested return
mock_decode = MagicMock(return_value='["myjsondata"]')
# second nested return value
mock_response = MagicMock()
mock_response.read.return_value=mock_decode
# first nested return value
mock_urlopen.return_value = mock_response
### trying to simplify all of this
load_json()
这就是我到目前为止嘲笑这个问题的方法,它非常不优雅,使维护变得复杂:
mock_urlopen.__enter__.loads.__enter__.decode.return_value = '["myjsondata"]'
最后,我试图模拟的是来自解码函数的返回数据,它来自url open函数。 这可能是一行或更简单的方法,可能使用输入方法。 理想情况下,mock会在test_load_json函数中看起来像这样:
max-width
不幸的是,我似乎无法在模拟文档中找到任何有用的东西。任何帮助表示赞赏。
答案 0 :(得分:21)
事实证明这很容易并且有记录。但是,命名并不简单,需要知道自己在寻找什么。引用的模拟是链接调用,实际上是在模拟库中记录的。
在此示例中,mock_urlopen应如下所示:
mock_urlopen.return_value.read.return_value.decode.return_value = '["myjsondata"]'
这很好用。有关更多详细信息,请查看python doc:https://docs.python.org/3/library/unittest.mock-examples.html#mocking-chained-calls
答案 1 :(得分:3)
我已经为你做了一个帮助类:
from unittest.mock import Mock
class ProxyMock:
"""Put me for easy referral"""
def __init__(self, mock, _first=True):
self._mock_ = mock
self._first_ = _first
def __getattr__(self, name):
if self._first_:
new_mock = getattr(self._mock_, name)
else:
new_mock = getattr(self._mock_.return_value, name)
return ProxyMock(new_mock, _first=False)
def __setattr__(self, name, value):
if name in ("_mock_", "_first_"):
return super().__setattr__(name, value)
setattr(self._mock_, name, value)
a = Mock()
ProxyMock(a).b.c.return_value = 123
assert a.b().c() == 123