如何断言被Patch的request.get()调用传入的URL参数?
我来给你捋捋怎么解决这个问题哈~你现在的问题是用@mock.patch('request.get', new=mock_response_200)这种方式替换原函数后,测试函数里拿不到mock的调用记录,没法断言传入的URL。这里有两种常用的解决方案:
方法一:利用mock的side_effect和注入的mock对象(推荐)
这种方法既保留了你自定义的mock响应逻辑,又能借助mock库自带的调用记录功能来做断言,是更规范的做法:
首先修改你的测试脚本,去掉new参数,改用side_effect,同时让测试函数接收patch生成的mock对象作为参数:
def mock_response_200(url): response = mock.MagicMock() response.status_code = 200 response.json = mock.Mock(return_value={ 0: {'key1': 'value1', 'key2': 'value2'} }) return response @mock.patch('request.get') # 这里不再指定new参数 def test_get_data(mock_get): # 让mock对象的side_effect指向我们的自定义响应函数 mock_get.side_effect = mock_response_200 arg1 = 'arg1' arg2 = None arg3 = 'arg3' stuff = get_data(arg1, arg2, arg3) # 断言request.get被调用时传入的URL是否符合预期 mock_get.assert_called_once_with('some_url?arg1&arg3')
原理说明:
当你用@mock.patch('request.get')而不指定new时,mock库会自动创建一个Mock实例来替代原函数,并把这个实例注入到测试函数的参数(这里是mock_get)中。我们给这个mock对象的side_effect赋值为你的mock_response_200函数,这样每次调用request.get()时,都会执行mock_response_200并返回你定义的响应,同时mock_get会自动记录所有的调用参数,你就可以用assert_called_once_with()来验证传入的URL是否正确了。
方法二:在自定义mock函数中记录调用参数
如果你不想修改patch的方式,也可以在mock_response_200里添加一个变量来记录每次调用的URL:
def mock_response_200(url): # 给函数添加一个属性来存储调用过的URL(用列表是因为它是可变对象,能在外部访问) if not hasattr(mock_response_200, 'called_urls'): mock_response_200.called_urls = [] mock_response_200.called_urls.append(url) response = mock.MagicMock() response.status_code = 200 response.json = mock.Mock(return_value={ 0: {'key1': 'value1', 'key2': 'value2'} }) return response @mock.patch('request.get', new=mock_response_200) def test_get_data(): arg1 = 'arg1' arg2 = None arg3 = 'arg3' # 先清空记录,避免其他测试用例的影响 mock_response_200.called_urls.clear() stuff = get_data(arg1, arg2, arg3) # 断言调用的URL是否正确 assert mock_response_200.called_urls == ['some_url?arg1&arg3']
这种方法的思路是利用函数作为对象的特性,给它动态添加一个属性来存储调用记录,之后在测试函数里直接检查这个属性即可。不过相比第一种方法,它需要自己维护调用记录的状态,容易受其他测试用例的影响,所以更推荐第一种方案。
内容的提问来源于stack exchange,提问作者Koen




