I'm attempting to test a a method that is memoized through lru_cache
(since it's an expensive database call). with pytest-mock
.
A simplified version of the code is:
class User:
def __init__(self, file):
# load a file
@lru_cache
def get(self, user_id):
# do expensive call
Then I'm testing:
class TestUser:
def test_get_is_called(self, mocker):
data = mocker.ANY
user = User(data)
repository.get(user_id)
open_mock = mocker.patch('builtins.open', mocker.mock_open())
open_mock.assert_called_with('/foo')
But I'm getting the following error:
TypeError: unhashable type: '_ANY'
This happens because functools.lru_cache
needs the keys stored to be hashable i.e. have a method __hash__
or __cmp__
implemented.
How can I mock such methods in a mocker to make it work?
I've tried
user.__hash__.return_value = 'foo'
with no luck.
Instead of using mocker.ANY
(an object which is intented to be used in assertions as a placeholder that's equal to any object) I believe you instead want to use a sentinel object (such as mocker.sentinel.DATA
).
This appears to work from a quick test:
from functools import lru_cache
@lru_cache(maxsize=None)
def f(x):
return (x, x)
def test(mocker):
ret = f(mocker.sentinel.DATA)
assert ret == (mocker.sentinel.DATA, mocker.sentinel.DATA)