Reputation: 11337
I'm using the @cache
decorator in my methods:
class Configuration:
@classmethod
@property
@cache
def whitelist_sections(cls) -> Set[int]:
whitelist_sections: Set[int] = set()
whitelist: str = os.getenv("WHITELIST_SECTIONS", "")
try:
whitelist_sections = eval("{" + whitelist + "}")
except ValueError:
return whitelist_sections
return whitelist_sections
I want to test the method above, here are my efforts:
def test_whitelist_sections():
section_id = 8765432
env_var_mock = mock.patch.dict(os.environ, {"WHITELIST_SECTIONS": str(section_id)})
env_var_mock.start()
whitelist_sections = Configuration.whitelist_sections
env_var_mock.stop()
assert whitelist_sections == {section_id}
def test_whitelist_multiple_sections():
section_id_1 = 8765432
section_id_2 = 1234567
env_var_mock = mock.patch.dict(os.environ, {"WHITELIST_SECTIONS": f"{section_id_1},{section_id_2}"})
env_var_mock.start()
whitelist_sections = Configuration.whitelist_sections
env_var_mock.stop()
assert whitelist_sections == {section_id_1, section_id_2}
def test_whitelist_sections_empty():
env_var_mock = mock.patch.dict(os.environ, {"WHITELIST_SECTIONS": ""})
env_var_mock.start()
whitelist_sections = Configuration.whitelist_sections
env_var_mock.stop()
assert whitelist_sections == {}
The problem is the cache which doesn't allow me to test different scenarios. How can I mock the @cache
decorator?
I tried this approach but it didn't work:
cache_mock = mock.patch("functools.cache", lambda func: func)
EDIT: tried this approach:
def mock_cache(function):
return function()
def test_whitelist_sections():
section_id = 8765432
env_var_mock = mock.patch.dict(os.environ, {"WHITELIST_SECTIONS": str(section_id)})
env_var_mock.start()
cache_mock = mock.patch("my_module.configuration.cache", mock_cache)
cache_mock.start()
whitelist_sections = Configuration.whitelist_sections
cache_mock.stop()
env_var_mock.stop()
assert whitelist_sections == {section_id}
Running in debug mode I can see that the decorator was replaced by mock_cache
but running all together with pytest
still yield the same error for two (out of free) tests - only first one work
EDIT2: note that that's a static method (@classmethod
)
Upvotes: 3
Views: 2716
Reputation: 111
The @cache
decorator adds a cache_clear
attribute to the function that it decorates, so the simplest approach is to add this line to your test before you call the cached function:
whitelist_sections.cache_clear()
If you find yourself doing this in a lot of your tests, you can make an auto-use fixture which always clears this cache.
@pytest.fixture(autouse=True)
def clear_caches():
whitelist_sections.cache_clear()
other_cached_function.cache_clear()
Add it either in your test file or a suitably located conftest.py
file to affect all tests recursively in that module.
Upvotes: 9
Reputation: 15573
For the ones using cachetools
package, you need to use the cache_clear
method. For example if your function is something like this:
from cachetools.func import ttl_cache
@ttl_cache(maxsize=100, ttl=360)
def foo(x):
# Do somthing with x
Then you can create a fixture
with pytest
like this:
@pytest.fixture(autouse=True)
def clear_cache():
yield
foo.cache_clear()
Upvotes: 1