模拟时生成的响应在 python 测试中不正确

Response generated while mocking is not correct in python tests

我正在尝试使用 python 中的模拟对我的一些函数进行单元测试。他们中很少有人像预期的那样工作,但我对其中一个测试用例的响应感到困惑。它没有返回它应该返回的理想响应。

###############motpenrichreceiverinfo.py##################

import requests

def getReceiverInfo(fundId):
    print('Inside fetchReceiverInfo',fundId)
    response = requests.get("REST URL FOR RECEIVER INFO")
    if response.ok:
        return response
    else:
        return None
    
def getMotpTrade(trade_id):
    response = requests.get("REST URL")
    if response.ok:
        return response
    else:
        return None

def getMotpCanonical(trade_id):
    response = requests.get("REST URL")
    if response.ok:
        return response
    else:
        return None
    
def EnrichTradeWithReceiverInfo(event, context):
    #print('Lambda function started..')
    trade_id = event['tradeId']
    motpTrade = getMotpTrade(trade_id)
    canonicalTrade = getMotpCanonical(trade_id)

    fundId = motpTrade['Account']
    #print(fundId)
    data = getReceiverInfo(fundId)
    print(data)
    return data

##########################test_motptrade.py############## ################

# Standard library imports
from unittest.mock import Mock, patch

# Third-party imports...
from nose.tools import assert_true
from nose.tools import assert_is_not_none, assert_list_equal, assert_dict_equal

# Local imports
from motpenrichreceiverinfo import getMotpTrade, getReceiverInfo, EnrichTradeWithReceiverInfo

@patch('motpenrichreceiverinfo.requests.get')
def test_motptraderequest_response(mock_get):
    motpTrade = [{
            "motpTrade":"motpTrade"
    }]

    # Configure the mock to return a response with an OK status code.
    mock_get.return_value.ok = True
    mock_get.return_value.json.return_value = motpTrade
    
    # Send a request to the API server and store the response.
    response = getMotpTrade('tradeId')

    # If the request is sent successfully, then I expect a response to be returned.
    assert_list_equal(response.json(), motpTrade)

@patch('motpenrichreceiverinfo.requests.get')
def test_getReceiverInfo_respose_ok(mock_get):
    receiverInfo = [{
        "reciever":"reciever"
    }]

    # Configure the mock to return a response with an OK status code.
    mock_get.return_value.ok = True
    mock_get.return_value.json.return_value = receiverInfo
    
    # Send a request to the API server and store the response.
    response = getReceiverInfo("1110")

    # If the request is sent successfully, then I expect a response to be returned.
    assert_list_equal(response.json(), receiverInfo)

@patch('motpenrichreceiverinfo.getMotpTrade')
@patch('motpenrichreceiverinfo.getMotpCanonical')
@patch('motpenrichreceiverinfo.getReceiverInfo')
def test_EnrichTradeWithReceiverInfo_ok(mock_get,mock_canonical,mock_receiverinfo):
    motpTrade = [{
            "motpTrade":"motpTrade"
    }]
    
    receiverInfo = [{
            "reciever":"reciever"
        }]
    event = {"tradeId":"123456"}
    
    # Configure the mock to return a response with an OK status code.
    mock_get.return_value = Mock(ok=True)
    mock_get.return_value.json.return_value = motpTrade

    mock_canonical.return_value.ok = True
    mock_canonical.return_value.json.return_value = [{}]

    mock_receiverinfo.return_value.ok = True
    mock_receiverinfo.return_value.json.return_value = receiverInfo
    
    data = EnrichTradeWithReceiverInfo(event,"")
    assert_true(mock_get.called)
    assert_true(mock_receiverinfo.called)
    assert_list_equal(data.json(),receiverInfo) 

这里我的前两个案例按预期工作。但是我的最后一个测试用例(test_EnrichTradeWithReceiverInfo_ok)不知何故不起作用。理想情况下,当我 运行 它给出以下错误时,它的响应应该等于 receiverInfo object.But。如果有人能帮助我理解我在这里做错了什么,那将非常有帮助。

(venv) C:\Development\motplambdas>nosetests -v test_motptrade.py
test_motptrade.test_EnrichTradeWithReceiverInfo_ok ... FAIL
test_motptrade.test_getReceiverInfo_respose_ok ... ok
test_motptrade.test_motptraderequest_response ... ok

======================================================================
FAIL: test_motptrade.test_EnrichTradeWithReceiverInfo_ok
----------------------------------------------------------------------
Traceback (most recent call last):
  File "c:\development\motplambdas\venv\lib\site-packages\nose\case.py", line 198, in runTest
    self.test(*self.arg)
  File "c:\program files\python38\lib\unittest\mock.py", line 1325, in patched
    return func(*newargs, **newkeywargs)
  File "C:\Development\motplambdas\test_motptrade.py", line 69, in test_EnrichTradeWithReceiverInfo_ok
    assert_list_equal(data.json(),receiverInfo)
AssertionError: Lists differ: [{'motpTrade': 'motpTrade'}] != [{'reciever': 'reciever'}]

First differing element 0:
{'motpTrade': 'motpTrade'}
{'reciever': 'reciever'}

- [{'motpTrade': 'motpTrade'}]
+ [{'reciever': 'reciever'}]

----------------------------------------------------------------------
Ran 3 tests in 0.011s

FAILED (failures=1)

问题在于您将 Mock 对象传递给函数调用的顺序。

@patch('motpenrichreceiverinfo.getMotpTrade')
@patch('motpenrichreceiverinfo.getMotpCanonical')
@patch('motpenrichreceiverinfo.getReceiverInfo')
def test_EnrichTradeWithReceiverInfo_ok(mock_get,mock_canonical,mock_receiverinfo)

Mock对象是自下而上传递的,意思是@patch('motpenrichreceiverinfo.getReceiverInfo')是第Mock传递给函数调用的,不是你列出的最后一个。因此,您最终将 getReceiverInfo 设置为 return 错误的值。解决方案是将函数调用切换为如下所示:

def test_EnrichTradeWithReceiverInfo_ok(mock_receiverinfo, mock_canonical, mock_get)

您可以阅读更多相关内容 here,其中解释了嵌套装饰器的工作原理。

Note that the decorators are applied from the bottom upwards. This is the standard way that Python applies decorators. The order of the created mocks passed into your test function matches this order.