Python 在模拟模块时模拟访问 "real" 个对象

Python mock access "real" objects while mocking a module

是否可以在模拟模块时访问 "real" 对象?我想做的是模拟一些函数,但是抛出 "real" 异常,像这样:

@mock.patch('my_project.requests')
def test_foo(self,  mock_requests):

    mock_requests.post = mock.Mock(side_effect=requests.ConnectionError())

    thread = CommandThread("command", 3, 2, 0)
    thread.run() #this is were I exercise requests.post

    self.assert(thread.was_successful is False)

在我的 CommandThread 中,我有一个类似

的检查
try:
    requests.post(url, data=data)
except (requests.ConnectionError, requests.Timeout):
    self.was_successful = False

然而,我的测试失败了,因为异常没有在 try/except 块中捕获(当我喜欢 except Exception: 时它起作用了) 我认为,原因很简单,因为我在我的测试用例中嘲笑了这个 "namespace",所以我实际上从原始包中引发了 my_project.requests.ConnectionError 异常,而不是正确的 requests.ConnectionError。 是否有可能 access/throw "real" 异常?

发生这种情况是因为您的模拟实际上覆盖了代码中的整个请求模块。以下是调试方法:

在您的代码中添加:

try:
    requests.post('', data='')
except (requests.ConnectionError, requests.Timeout):
    was_successful = False
except Exception, err:
    import pdb
    pdb.set_trace()

当您 运行 测试时,您将进入调试器,以便您可以查看发生了什么。如果我们查看您捕获的内容,这就是我们所看到的:

(Pdb) requests.ConnectionError
<MagicMock name='requests.ConnectionError' id='4562438992'>

您实际上捕获了一个模拟 ConnectionError,因为您的模拟修补了整个请求模块并且您正在输入一个真实的请求错误。

您可以通过使您的 mock 更具体并且只覆盖请求模块上的 post 方法来解决此问题:

@mock.patch('my_project.requests.post')
def test_foo(self,  mock_requests):
    mock_requests.side_effect = requests.ConnectionError()
    ...