我从一个代表 DynamoDB 数据库表的类开始:
from pynamodb.models import Model
class FooModel(Model):
class Meta:
table_name = "foo"
…
我有几个涉及这个类的测试。他们中的一些人以永远不会真正与云对话的方式使用FooModel
实例(我已经通过使用pytest-socket的--disable-socket
标志来确保这一点)。
问题是因为 Reasons™ 我已经更改了要由云提供商生成的表名。这意味着任何实际需要的生产代码都table_name
必须与云提供商联系。现在,如果我只是简单地进行table_name = get_table_name(…)
离线测试将失败,因为该代码是在导入时执行的。但是,我仍然希望单元测试脱机运行,因此我将该字段更改为一个属性,该属性调用一个方法来在运行时查找实际值:
@property
@classmethod
def table_name(cls) -> str:
return get_table_name(…)
这使得离线测试通过而无需引入任何复杂的模拟框架或在测试和生产期间运行不同的代码路径。问题是验收测试(针对已部署的云基础设施运行)失败,因为 boto3 正在尝试将属性序列化为 JSON 并且失败:
self = <json.encoder.JSONEncoder object at 0x7f65ad5b0400>, o = <property object at 0x7f65ab46d450>
def default(self, o):
"""Implement this method in a subclass such that it returns
a serializable object for ``o``, or calls the base implementation
(to raise a ``TypeError``).
For example, to support arbitrary iterators, you could
implement default like this::
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
# Let the base class default method raise the TypeError
return JSONEncoder.default(self, o)
"""
> raise TypeError(f'Object of type {o.__class__.__name__} '
f'is not JSON serializable')
E TypeError: Object of type property is not JSON serializable
../../.pyenv/versions/3.8.6/lib/python3.8/json/encoder.py:179: TypeError
如何在不引入更多框架并确保生产代码路径与测试代码路径相同的情况下解决此问题?