如何使用pytest-mock模拟Python中的链式函数调用?
链式调用Mock解决方案
错误原因
你之前自己创建的独立MagicMock实例没有和实际业务代码里引用的app.Application绑定,所以业务代码调用时根本不会走到你定义的mock逻辑,自然不生效。
正确实现方案
对于Application.objects(id=xxx).first()这类两层链式调用,只需要给objects方法的返回值绑定first方法的mock返回值即可,代码如下:
def test_update_application(client, mocker): # 构造假的Application实例 test_application = Application( id=4, jobTitle='fakeJob12345', companyName='fakeCompany', date=str(datetime.date(2021, 9, 22)) ) # 1. Mock Application.objects方法 mock_objects = mocker.patch('app.Application.objects') # 2. 给objects调用后的返回值,设置first方法的返回值为假实例 mock_objects.return_value.first.return_value = test_application # 3. 可选:Mock后续的application.update方法 mock_update = mocker.patch.object(test_application, 'update') # 发起请求 rv = client.put('/application', json={ 'application':{ 'id':2, 'jobTitle':'fakeJob12345', 'companyName':'fakeCompany', 'date':str(datetime.date(2021, 9, 23)), 'status':'1' } }) # 校验逻辑 print(rv.data) # 注:你粘贴的原接口代码有截断,需确保接口成功分支返回了对应结构,再调整断言即可 jdata = json.loads(rv.data.decode("utf-8"))["jobTitle"] assert jdata == 'fakeJob12345' # 额外可选校验:update方法是否按入参调用 mock_update.assert_called_once_with( jobTitle='fakeJob12345', companyName='fakeCompany', date=str(datetime.date(2021, 9, 23)), status='1' )
原理解释
- 调用
mocker.patch('app.Application.objects')时,返回的mock_objects就是对Application.objects方法的mock对象 mock_objects.return_value对应Application.objects(id=xxx)调用完成后的返回值- 再给这个返回值的
first方法设置return_value,就对应Application.objects(id=xxx).first()的返回值 - 如果是更长的链式调用,比如
a.b().c().d(),只要依次给每一层的return_value的下一个方法设置返回值即可
内容的提问来源于stack exchange,提问作者Setu Kumar Basak
相关产品推荐
相关产品推荐

