I started with a class representing a DynamoDB database table:
from pynamodb.models import Model
class FooModel(Model):
class Meta:
table_name = "foo"
…
I've got several tests involving this class. Some of them use FooModel
instances in such a way as to never actually talk to the cloud (I've ensured this by using pytest-socket's --disable-socket
flag).
The problem is that for Reasons™ I have changed the table name to be generated by the cloud provider. This means that any production code which actually needs the table_name
must talk to the cloud provider. Now, if I simply do table_name = get_table_name(…)
the offline tests will fail, because that code is executed at import time. I still want the unit tests to run offline, however, so I've changed the field into a property which calls a method to look up the actual value at runtime:
@property
@classmethod
def table_name(cls) -> str:
return get_table_name(…)
This makes the offline tests pass without introducing any complex mocking frameworks or running a different code path during tests and production. The problem is that the acceptance tests (which run against a deployed cloud infrastructure) are failing because boto3 is trying and failing to serialize the property into 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
How do I work around this without introducing any more frameworks and making sure the production code path remains the same as the test code path?
Related issue & actual code in case you want to look at either.