How to unit-test a Flask-Caching memoized function?

331 Views Asked by At

I'm using:

Python 3.9.13
pytest==7.2.0
pytest-mock==3.10.0
Flask==2.2.2
Flask-Caching==2.0.1

This is my class being tested:

@dataclass(frozen=True)
class NominationData:
    title: str
    url: str
    is_approved: bool
    articles: list[ArticleData]
    hooks: list[HookData]

    @staticmethod
    @cache.memoize(timeout=30)
    def from_nomination(nomination):
        """Construct a NominationData from a dyk_tools.Nomination"""
        return NominationData(
            nomination.title(),
            nomination.url(),
            nomination.is_approved(),
            [ArticleData.from_article(a) for a in nomination.articles()],
            [HookData.from_hook(h) for h in nomination.hooks()],
        )

I've got a unit test for NominationData.from_nomination() which previously worked in a non-memoized version. Now that I've added the @cache.memoize() decoration, the test crashes in flask_caching/__init__.py:870 with AttributeError: 'Cache' object has no attribute 'app'. It's obvious what the problem is: I don't have a valid application context in flask.current_app. The question is, what's the best way to fix that?

One possibility would be to patch flask.current_app with a mock AppContext, but I'm hesitant to go down that path. Another possibility would be to split out the memoization into a distinct shim:

@staticmethod
@cache.memoize(timeout=30)
def from_nomination(nomination):
    return inner_from_nomination(nomination)

and then just call inner_from_nomination() in my unit test. That should work, but just feels wrong. Or maybe there's some cleaner way entirely? How would you do this?

1

There are 1 best solutions below

0
On

Oh, I get it. I need to change my unit test to call the .uncached function directly:

-  nomination_data = NominationData.from_nomination(nomination)
+  nomination_data = NominationData.from_nomination.uncached(nomination)

https://flask-caching.readthedocs.io/en/latest/api.html#flask_caching.Cache.memoize