我从一个代表 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
如何在不引入更多框架并确保生产代码路径与测试代码路径保持相同的情况下解决这个问题?
Related issue 和 actual code,以防您想查看其中任何一个。