I have a function that I am writing unit tests for using pytest. The only problem is that since I am writing multiple tests for the same function, a couple of tests fail because of the cachetools.ttl_cache decorator. This decorator makes the function return the same value every time it is being run which messes up the tests. This decorator is not present in the function that I am testing but in a function that is called by the one that I am testing. I cannot remove this decorator from the function I am testing. Here is the test:
@patch('load_balancer.model_helpers.DBSession')
def test_returns_true_if_split_test_is_external(self, dbsession, group_ctx):
group_ctx.group_id = '{}-{}'.format('2222222222', '123456789')
split_test = Mock()
split_test.state = 'external'
config = {
'query.return_value.filter.return_value.first.return_value': split_test
}
dbsession.configure_mock(**config)
assert group_ctx.is_in_variation_group('foo') == True
And here is the function to be tested:
def is_in_variation_group(self, split_test=None):
try:
split_test = get_split_test(split_test) # This function has the
#decorator
log.info('Split test {} is set to {}'.format(split_test.name,
split_test.state))
if not split_test or split_test.state == 'off':
return False
phone_number = int(self.group_id.split('-')[0])
if split_test.state == 'internal':
return True if str(phone_number) in INTERNAL_GUINEA_PIGS else False
if split_test.state == 'external':
return True if phone_number % 2 == 0 else False
except Exception as e:
log.warning("A {} occurred while evaluating membership into {}'s variation "
"group".format(e.__class__.__name__, split_test))
Get split test function:
@cachetools.ttl_cache(maxsize=1024, ttl=60)
def get_split_test(name):
return (DBSession.query(SplitTest)
.filter(SplitTest.name == name)
.first())
How can I make it so this cache decorator is ignored? Any help is appreciated greatly
I suggest clearing the function's cache after each test run.
The cachetools documentation doesn't mention this, but from the source code it appears the cache decorators expose a cache_clear
function.
For your example code under test:
import cachetools.func
@cachetools.func.ttl_cache(maxsize=1024, ttl=60)
def get_split_test(name):
return (DBSession.query(SplitTest)
.filter(SplitTest.name == name)
.first())
This would be my approach (assumes pytest >= 3, otherwise use the yield_fixture
decorator):
@pytest.fixture(autouse=True)
def clear_cache():
yield
get_split_test.cache_clear()
def test_foo():
pass # Test your function like normal.
That clear_cache
fixture uses a yield fixture that is automatically used after each test (autouse=True
) to perform the cleanup after each test. You also can use the request
fixture and request.addfinalizer
to run a cleanup function.
I would assign the cache into a variable and then at the end of the test reset the cache
GET_USERS_CACHE = TTLCache(maxsize=128, ttl=60)
@cached(cache=GET_USERS_CACHE)
def get_users():
pass
test file
def test_get_users():
# test code here
GET_USERS_CACHE.clear()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With