如何让mock.mock_open引发IOError?

17

我需要测试一个调用open方法的实例方法。在第一个测试用例中,我设置了mock.mock_open返回一个字符串,如预期一样。这很好地工作。

然而,我还需要测试从该函数抛出IOError的情况。我该如何使mock.mock_open引发任意异常?

到目前为止,这是我的方法:

@mock.patch.object(somemodule, 'generateDefaultKey')
def test_load_privatekey(self, genkey)
    mo = mock.mock_open(read_data=self.key)
    mo.side_effect = IOError
    with mock.patch('__main__.open', mo, create=True):
        self.controller.loadPrivkey()

    self.assertTrue(genkey.called, 'Key failed to regenerate')
2个回答

22

将异常分配给mock.mock_open.side_effect

mock.mock_open.side_effect = IOError

来自mock.Mock.side_effect文档:

这可以是在调用模拟对象时要调用的函数,也可以是要引发的异常(类或实例)。

演示:

>>> mock = MagicMock()
>>> mock.mock_open.side_effect = IOError()
>>> mock.mock_open()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/site-packages/mock.py", line 955, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/site-packages/mock.py", line 1010, in _mock_call
    raise effect
IOError

使用patch()作为上下文管理器时,会产生一个新的模拟对象;将其分配给那个模拟对象:

with mock.patch('__main__.open', mo, create=True) as mocked_open:
    mocked_open.side_effect = IOError()
    self.controller.loadPrivkey()

这个应该如何在TestCase函数中使用?我已经编辑了我的答案,展示了我最新的尝试--也许你能发现我的错误! - Louis Thibault
1
@blz:patch()上下文管理器返回一个模拟对象。我会更新。 - Martijn Pieters
非常感谢!我对Mock还很陌生,但只要有人向你展示如何操作,它其实就很简单 =) - Louis Thibault
你为每个 Python 版本都有一个 SO 虚拟环境吗? - Simeon Visser
@Simeon:仅适用于2.7和3.3。 - Martijn Pieters

7

我觉得Martijn的答案有点难以概括,所以这里是我希望更简单一些、与OP最初代码不太相关的答案:

from unittest.mock import patch, mock_open


def func_to_test():
    try:
        with open('path/to/open', 'r') as file:
            return 1

    except IOError:
        return 2


def test_open_error():
    with patch("builtins.open", mock_open()) as mock_file:
        mock_file.side_effect = IOError()

        assert func_to_test() == 2

        mock_file.assert_called_with('path/to/open', 'r')

值得注意的是,如果你只想抛出一个异常,那么没有必要使用 mock_open(),普通的 mock 就可以胜任。 - Erpheus
2
在这种情况下,您可以将 with patch 行更改为 with patch("builtins.open") as mock_file: - Erpheus
谢谢你的回答。 - justnisar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接