如何Mock依赖类的方法?——解决测试Creator.do_a_call时Mock Requester.make_request出现的AttributeError问题
解决Mock Requester.make_request时的AttributeError问题
你遇到的问题核心是mock返回的不是requests.Response实例,而是requests-mock的_Matcher对象,所以代码里访问response.status_code时会触发AttributeError。下面我来一步步帮你修正这个问题:
问题根源
你的mocked_make_request方法里用了requests_mock.Mocker.post(),这个方法返回的是一个用于匹配请求的_Matcher对象,而不是我们需要的requests.Response实例。既然已经通过@patch mock了Requester.make_request方法,我们完全不需要再用requests-mock来拦截请求,直接手动构造符合要求的Response对象即可。
修正方案
1. 改写mock方法,返回正确的Response实例
我们直接创建requests.Response对象,设置好需要的属性(比如status_code、响应内容等),这样就能让Creator.do_a_call正常处理返回值:
def mocked_make_request(self, path, method='get', body=None, custom_headers=None): # 手动构造Response实例 response = Response() # 设置状态码,根据测试场景调整 response.status_code = 200 # 设置响应内容(_content是Response内部存储内容的属性,需要bytes类型) response._content = b'{"result": "success"}' # 如果需要响应文本,可以直接设置text属性(可选) response.text = '{"result": "success"}' return response
注意:这里的参数要和原make_request方法的参数完全匹配(原方法参数是path, method, body, custom_headers),之前你的mocked_make_request用了two, three作为参数名,会导致参数不匹配的问题,一定要修正。
2. 修正测试用例
用side_effect的测试
@patch('Requester.Requester.make_request') def test_do_a_call_side_effect(self, make_request): creator = Creator() # 将side_effect指向我们的mock方法 make_request.side_effect = self.mocked_make_request response = creator.do_a_call("mock://test.com") self.assertEqual(200, response.status_code)
用return_value的测试
@patch('Requester.Requester.make_request') def test_do_a_call_return_value(self, make_request): creator = Creator() # 直接返回构造好的Response实例 mock_response = Response() mock_response.status_code = 200 mock_response._content = b'{"result": "success"}' make_request.return_value = mock_response response = creator.do_a_call("mock://test.com") self.assertEqual(200, response.status_code)
完整修正后的test.py
import unittest from unittest.mock import patch from Creator import Creator from requests import Response from http import HTTPStatus as status class CreatorTest(unittest.TestCase): def mocked_make_request(self, path, method='get', body=None, custom_headers=None): response = Response() response.status_code = status.OK response._content = b'{"message": "Success"}' response.text = '{"message": "Success"}' return response @patch('Requester.Requester.make_request') def test_do_a_call_side_effect(self, make_request): creator = Creator() make_request.side_effect = self.mocked_make_request response = creator.do_a_call("mock://test.com") self.assertEqual(status.OK, response.status_code) @patch('Requester.Requester.make_request') def test_do_a_call_return_value(self, make_request): creator = Creator() mock_response = Response() mock_response.status_code = status.OK mock_response._content = b'{"message": "Success"}' mock_response.text = '{"message": "Success"}' make_request.return_value = mock_response response = creator.do_a_call("mock://test.com") self.assertEqual(status.OK, response.status_code) if __name__ == "__main__": unittest.main()
额外提示:测试异常场景
如果要测试do_a_call抛出异常的情况(比如状态码不是200或202),只需要构造对应状态码的Response即可:
def test_do_a_call_raises_exception(self): with patch('Requester.Requester.make_request') as make_request: mock_response = Response() mock_response.status_code = status.BAD_REQUEST mock_response.text = 'Invalid request' make_request.return_value = mock_response creator = Creator() with self.assertRaises(Exception) as context: creator.do_a_call("mock://test.com") # 验证异常内容 self.assertEqual(context.exception.args[0], status.BAD_REQUEST) self.assertEqual(context.exception.args[1], 'Invalid request')
内容的提问来源于stack exchange,提问作者roflcopter1101
相关产品推荐
相关产品推荐

