是否可以在Python模拟对象中查询其调用的返回值?

时间:2014-10-31 09:19:23

标签: python python-3.x python-mock

Python 3 mock objects支持查询其调用的参数,是否可以查询它们的调用返回的值?

我的特殊情况是我模拟tempfile.mkdtemp,但作为副作用调用真正的mkdtemp。我想在我的测试中掌握创建的临时目录。

from unittest import mock
import shutil
import tempfile

from app import production_function


def mkdtemp(*args, **kwargs):
    dtemp = orig_mkdtemp(*args, **kwargs)
    return dtemp


orig_mkdtemp = tempfile.mkdtemp
patcher = mock.patch('tempfile.mkdtemp', name='tempfile.mkdtemp')
the_mock = patcher.start()
the_mock.side_effect = mkdtemp

# Call function under test
production_function()

assert the_mock.called
# Now, how to get the return value from the call to the_mock?

patcher.stop()

2 个答案:

答案 0 :(得分:1)

不幸的是mock模块没有存储返回值(我看了一下debugguer并且没有任何跟踪)。您必须先存储它,然后才能返回side_effect

的值

您可以使用对象来处理脏工作。例如,一个非常基础的实现可以是这样的:

class SideEffect():
    def __init__(self, n):
        self.values = iter(range(n))
        self.return_value = None

    def __call__(self):
        self.return_value = next(self.values)
        return self.return_value


a = Mock()
se = SideEffect(10)
a.side_effect = se

for x in range(10):
    v = a()
    assert v == se.return_value
    print("a()={}  return_value={}".format(v, se.return_value))

如果你想要一个更复杂的side_effect来包装一个函数并处理参数和异常,可以是一个例子:

class GenericSideEffect():
    def __init__(self, f, *args, **kwargs):
        self.v_function = f
        self.args = args
        self.kwargs = kwargs
        self._return_value = Exception("Never Called")

    def __call__(self):
        try:
            self._return_value = self.v_function(*self.args, **self.kwargs)
            return self._return_value
        except Exception as e:
            self.return_value = e
            raise e

    @property
    def return_value(self):
        if isinstance(self._return_value, Exception):
            raise self._return_value
        return self._return_value

当然你可以把它写成装饰器并保留签名,但我认为那部分超出了答案的范围。

答案 1 :(得分:0)

如果comportment是确定性的并且状态较少,则可以获得对mock进行的调用列表,并再次调用您感兴趣的嵌套调用来捕获结果。另外我想你可以做类似的事情:

def mkdtemp_wrapper(result_storage):
    def mkdtemp(*args, **kwargs):
        dtemp = orig_mkdtemp(*args, **kwargs)
        result_storage.append(((*args,**kwargs),dtemp))
        return dtemp
    return mkdtemp

以这种方式修改模拟:

results_values = []
the_mocks.side_effect = mkdtemp_wrapper(result_values)

然后,您将在结果值中包含几个参数列表,结果。

希望它有所帮助。