Python pytest mock 失败,函数调用断言 "assert None"
Python pytest mock fails with "assert None" for function call assertions
我正在尝试模拟对 boto3 的一些调用,看起来模拟函数正在返回正确的值,而且看起来如果我更改断言,它就不再匹配断言中传递的内容,因为断言失败输入参数不匹配,但是如果我让它们匹配,则断言失败:
E AssertionError: assert None
E + where None = <bound method wrap_assert_called_with of <MagicMock name='get_item' id='139668501580240'>>(TableName='TEST_TABLE', Key={'ServiceName': {'S': 'Site'}})
E + where <bound method wrap_assert_called_with of <MagicMock name='get_item' id='139668501580240'>> = <MagicMock name='get_item' id='139668501580240'>.assert_called_with
E + where <MagicMock name='get_item' id='139668501580240'> = <botocore.client.DynamoDB object at 0x7f071b8251f0>.get_item
E + where <botocore.client.DynamoDB object at 0x7f071b8251f0> = site_dao.ddb_client
dynamo DB 对象是一个全局变量。
ddb_client = boto3.client("dynamodb")
def query_ddb():
"""Query dynamo DB for the current strategy.
Returns:
strategy (str): The latest strategy from dynamo DB.
"""
response = None
try:
ddb_table = os.environ["DDB_DA_STRATEGY"]
response = ddb_client.get_item(
TableName=ddb_table, Key={"ServiceName": {"S": "Site"}}
)
except Exception as exception:
LOGGER.error(exception)
raise ServerException("The server was unable to process your request.", [])
return response.get("Item").get("Strategy").get("S")
我的单元测试看起来像:
def test_data_access_context_strategy_ddb(mocker):
object_key = {
"ServiceName": {"S": "Site"}
}
table_name = "TEST_TABLE"
expected_response = "SqlServer"
os_env = {
"DDB_DA_STRATEGY": table_name,
}
ddb_response = {
"Item": {
"Strategy": {
"S": expected_response
}
}
}
mocker.patch.dict(os.environ, os_env)
mocker.patch.object(site_dao.ddb_client, "get_item")
site_dao.ddb_client.get_item.return_value = ddb_response
data_access_context = site_dao.DataAccessContext()
response = data_access_context.query_ddb()
assert response == expected_response
assert site_dao.ddb_client.get_item.assert_called_with(TableName=table_name, Key=object_key)
如果我更改 assert_called_with
的预期值,我无法弄清楚出了什么问题,例如:
assert site_dao.ddb_client.get_item.assert_called_with(TableName="TT", Key=object_key)
测试失败:
E AssertionError: expected call not found.
E Expected: get_item(TableName='TT', Key={'ServiceName': {'S': 'Site'}})
E Actual: get_item(TableName='TEST_TABLE', Key={'ServiceName': {'S': 'Site'}})
E
E pytest introspection follows:
E
E Kwargs:
E assert {'Key': {'Ser... 'TEST_TABLE'} == {'Key': {'Ser...leName': 'TT'}
E Omitting 1 identical items, use -vv to show
E Differing items:
E {'TableName': 'TEST_TABLE'} != {'TableName': 'TT'}
E Use -v to get the full diff
因此,当预期输入和实际输入不同时,它会因此而失败,但是当它们相同并且测试应该通过时,它会失败,因为就好像从未调用过该函数一样。
你在这一行有两个断言:
assert site_dao.ddb_client.get_item.assert_called_with(TableName=...)
第一个断言是 assert_called_with
,这听起来像是您想要的。然后在该行的开头有另一个断言:assert ...
断言 assert_called_with
函数的 return 值。当断言通过时,return 的值为 None
。因此,整行的计算结果为 assert None
,而 None
为 false-y,因此您最终得到 assert False
.
tl;dr 不要使用 assert
两次。
我正在尝试模拟对 boto3 的一些调用,看起来模拟函数正在返回正确的值,而且看起来如果我更改断言,它就不再匹配断言中传递的内容,因为断言失败输入参数不匹配,但是如果我让它们匹配,则断言失败:
E AssertionError: assert None
E + where None = <bound method wrap_assert_called_with of <MagicMock name='get_item' id='139668501580240'>>(TableName='TEST_TABLE', Key={'ServiceName': {'S': 'Site'}})
E + where <bound method wrap_assert_called_with of <MagicMock name='get_item' id='139668501580240'>> = <MagicMock name='get_item' id='139668501580240'>.assert_called_with
E + where <MagicMock name='get_item' id='139668501580240'> = <botocore.client.DynamoDB object at 0x7f071b8251f0>.get_item
E + where <botocore.client.DynamoDB object at 0x7f071b8251f0> = site_dao.ddb_client
dynamo DB 对象是一个全局变量。
ddb_client = boto3.client("dynamodb")
def query_ddb():
"""Query dynamo DB for the current strategy.
Returns:
strategy (str): The latest strategy from dynamo DB.
"""
response = None
try:
ddb_table = os.environ["DDB_DA_STRATEGY"]
response = ddb_client.get_item(
TableName=ddb_table, Key={"ServiceName": {"S": "Site"}}
)
except Exception as exception:
LOGGER.error(exception)
raise ServerException("The server was unable to process your request.", [])
return response.get("Item").get("Strategy").get("S")
我的单元测试看起来像:
def test_data_access_context_strategy_ddb(mocker):
object_key = {
"ServiceName": {"S": "Site"}
}
table_name = "TEST_TABLE"
expected_response = "SqlServer"
os_env = {
"DDB_DA_STRATEGY": table_name,
}
ddb_response = {
"Item": {
"Strategy": {
"S": expected_response
}
}
}
mocker.patch.dict(os.environ, os_env)
mocker.patch.object(site_dao.ddb_client, "get_item")
site_dao.ddb_client.get_item.return_value = ddb_response
data_access_context = site_dao.DataAccessContext()
response = data_access_context.query_ddb()
assert response == expected_response
assert site_dao.ddb_client.get_item.assert_called_with(TableName=table_name, Key=object_key)
如果我更改 assert_called_with
的预期值,我无法弄清楚出了什么问题,例如:
assert site_dao.ddb_client.get_item.assert_called_with(TableName="TT", Key=object_key)
测试失败:
E AssertionError: expected call not found.
E Expected: get_item(TableName='TT', Key={'ServiceName': {'S': 'Site'}})
E Actual: get_item(TableName='TEST_TABLE', Key={'ServiceName': {'S': 'Site'}})
E
E pytest introspection follows:
E
E Kwargs:
E assert {'Key': {'Ser... 'TEST_TABLE'} == {'Key': {'Ser...leName': 'TT'}
E Omitting 1 identical items, use -vv to show
E Differing items:
E {'TableName': 'TEST_TABLE'} != {'TableName': 'TT'}
E Use -v to get the full diff
因此,当预期输入和实际输入不同时,它会因此而失败,但是当它们相同并且测试应该通过时,它会失败,因为就好像从未调用过该函数一样。
你在这一行有两个断言:
assert site_dao.ddb_client.get_item.assert_called_with(TableName=...)
第一个断言是 assert_called_with
,这听起来像是您想要的。然后在该行的开头有另一个断言:assert ...
断言 assert_called_with
函数的 return 值。当断言通过时,return 的值为 None
。因此,整行的计算结果为 assert None
,而 None
为 false-y,因此您最终得到 assert False
.
tl;dr 不要使用 assert
两次。