在 Python 中对嵌套对象使用 Mock(DynamoDB 和 Table)
Using Mock in Python for nested objects (DynamoDB and Table)
我想用来自 DynamoDb 的不同输入测试函数的行为。有两种主要行为:当搜索键在 table 中找到时,当它不在时。这是函数的最小代码:
import boto3
from boto3.dynamodb.conditions import Key
def main(symbol):
dynamo = boto3.resource("dynamodb")
table = dynamo.Table("mytable")
data = table.query(KeyConditionExpression=Key("symbol").eq(symbol))
if data.count > 0:
# result = some_output
else:
result = {'status': '404'}
return result
我想通过发送空结果和非空项列表来通过单元测试来测试此代码,大致如下:
import boto3
import unittest
from unittest.mock import Mock, patch
class TestMainHandler(unittest.TestCase):
...
def test_main_fails_on_wrong_symbol(self):
with patch.object(main_handler, 'table') as get_mock:
get_mock.return_value = []
result = main('dummy_symbol')
expect_result = {'status': '404'}
self.assertEqual(result, expect_result)
但我不会 运行 模拟部分。我想知道您是否可以指导我如何模拟嵌套的 table 和发电机变量。非常感谢您的帮助。
我建议您尽可能先模拟 "integration point",然后以此为基础构建模拟结果。在这种情况下,它将是 boto3.resource
。从那里,您可以将 boto3.resource
的 return 值修改为模拟 table。然后,您可以将模拟 table 上任何调用的 return 值更改为您的预期结果。
import boto3
import unittest
from unittest.mock import Mock, patch
class TestMainHandler(unittest.TestCase):
@patch('boto3.resource')
def test_main_fails_on_wrong_symbol(self, mock_dynamo):
mock_table = Mock()
mock_table.query.return_value = []
mock_dynamo.Table.return_value = mock_table
result = main('dummy_symbol')
expected_result = {'status': '404'}
self.assertEqual(expected_result, result)
另请注意,我在测试用例上使用了补丁装饰器而不是上下文管理器。这是我的喜好问题,但我觉得它看起来更干净。
编辑:我在为 mock_dynamo
函数调用分配 return 值时出错。我还填了你的if
测试查询数据的长度和return什么的。但是这里的测试没有到达那个分支。这是最终产品:
"""boto_main.py"""
import boto3
from boto3.dynamodb.conditions import Key
def main(symbol):
dynamo = boto3.resource("dynamodb")
table = dynamo.Table("mytable")
data = table.query(KeyConditionExpression=Key("symbol").eq(symbol))
if len(data) > 0:
result = {'status': '200'}
else:
result = {'status': '404'}
return result
"""boto_test.py"""
import unittest
from unittest.mock import Mock, patch
from boto_main import main
class TestMainHandler(unittest.TestCase):
@patch('boto3.resource')
def test_main_fails_on_wrong_symbol(self, mock_dynamo):
mock_table = Mock()
mock_table.query.return_value = []
mock_dynamo.return_value.Table.return_value = mock_table
result = main('dummy_symbol')
expected_result = {'status': '404'}
self.assertEqual(expected_result, result)
我想用来自 DynamoDb 的不同输入测试函数的行为。有两种主要行为:当搜索键在 table 中找到时,当它不在时。这是函数的最小代码:
import boto3
from boto3.dynamodb.conditions import Key
def main(symbol):
dynamo = boto3.resource("dynamodb")
table = dynamo.Table("mytable")
data = table.query(KeyConditionExpression=Key("symbol").eq(symbol))
if data.count > 0:
# result = some_output
else:
result = {'status': '404'}
return result
我想通过发送空结果和非空项列表来通过单元测试来测试此代码,大致如下:
import boto3
import unittest
from unittest.mock import Mock, patch
class TestMainHandler(unittest.TestCase):
...
def test_main_fails_on_wrong_symbol(self):
with patch.object(main_handler, 'table') as get_mock:
get_mock.return_value = []
result = main('dummy_symbol')
expect_result = {'status': '404'}
self.assertEqual(result, expect_result)
但我不会 运行 模拟部分。我想知道您是否可以指导我如何模拟嵌套的 table 和发电机变量。非常感谢您的帮助。
我建议您尽可能先模拟 "integration point",然后以此为基础构建模拟结果。在这种情况下,它将是 boto3.resource
。从那里,您可以将 boto3.resource
的 return 值修改为模拟 table。然后,您可以将模拟 table 上任何调用的 return 值更改为您的预期结果。
import boto3
import unittest
from unittest.mock import Mock, patch
class TestMainHandler(unittest.TestCase):
@patch('boto3.resource')
def test_main_fails_on_wrong_symbol(self, mock_dynamo):
mock_table = Mock()
mock_table.query.return_value = []
mock_dynamo.Table.return_value = mock_table
result = main('dummy_symbol')
expected_result = {'status': '404'}
self.assertEqual(expected_result, result)
另请注意,我在测试用例上使用了补丁装饰器而不是上下文管理器。这是我的喜好问题,但我觉得它看起来更干净。
编辑:我在为 mock_dynamo
函数调用分配 return 值时出错。我还填了你的if
测试查询数据的长度和return什么的。但是这里的测试没有到达那个分支。这是最终产品:
"""boto_main.py"""
import boto3
from boto3.dynamodb.conditions import Key
def main(symbol):
dynamo = boto3.resource("dynamodb")
table = dynamo.Table("mytable")
data = table.query(KeyConditionExpression=Key("symbol").eq(symbol))
if len(data) > 0:
result = {'status': '200'}
else:
result = {'status': '404'}
return result
"""boto_test.py"""
import unittest
from unittest.mock import Mock, patch
from boto_main import main
class TestMainHandler(unittest.TestCase):
@patch('boto3.resource')
def test_main_fails_on_wrong_symbol(self, mock_dynamo):
mock_table = Mock()
mock_table.query.return_value = []
mock_dynamo.return_value.Table.return_value = mock_table
result = main('dummy_symbol')
expected_result = {'status': '404'}
self.assertEqual(expected_result, result)