如何模拟被模拟对象返回的对象?

0 投票
1 回答
1082 浏览
提问于 2025-04-21 10:36

我还不太懂Python中的mock(模拟)用法。

很明显,我不想让我的测试代码去调用实际的requests.post()方法,所以我想模拟它的行为:

def try_post(self, url, body):
    r = requests.post(url, data=body)
    msg = str(r.status_code) + " " + r.content + "\n"
    if r.status_code >= 300:
        sys.stderr.write("Error: POST returned " + msg)

我的问题是:我该如何模拟requests.post()返回的对象,也就是响应对象呢?

举个例子,我想写一个测试,让r.status_code是200,另一个测试让r.status_code是300,这样我就可以测试条件逻辑。另外,我还需要模拟r.content,让它返回一些字符串。

以下是我写的代码,但没有成功:

from monitor_writer import MonitorWriter
import mock
import unittest

class TestMonitorWriter(unittest.TestCase): 

    @mock.patch('monitor_writer.requests')
    def test_conforming_write(self, mock_requests):
        xml_frag = """
<InstantaneousDemand>
</InstantaneousDemand>
"""
        mock_requests.status_code.return_value = 200
        mock_requests.content.return_value = "OK"

        writer = MonitorWriter()
        writer.update(xml_frag)
        self.assertTrue(mock_requests.post.called, "Failed to call requests.post")

这个测试失败了,报错信息是TypeError: expected a character buffer object,因为r.status_code和r.content变成了mock.MagicMock对象,而不是字符串,导致try_post()方法试图把它们连接在一起时出错。

1 个回答

2

你想直接模拟 requests.post 这个函数,而不是整个 requests 模块:

class TestMonitorWriter(unittest.TestCase): 

    @mock.patch('monitor_writer.requests.post')
    def test_conforming_write(self, mock_post):
        xml_frag = """
<InstantaneousDemand>
</InstantaneousDemand>
"""
        response = mock.MagicMock()
        response.status_code = 200
        respone.content = "OK"
        mock_post.return_value = response

        writer = MonitorWriter()
        writer.update(xml_frag)
        self.assertTrue(mock_post.called, "Failed to call requests.post")

一旦我们模拟了你实际调用的那个函数,我们就创建一个模拟的响应对象,然后设置这个模拟响应的 status_code(状态码)和 content(内容)为你想要的值,最后把这个模拟的响应赋值给我们模拟的 post 函数的 return_value(返回值)。

撰写回答