使用lru_cache装饰器测试功能

时间:2019-01-24 16:18:28

标签: python mocking pytest functools

我正在尝试测试通过lru_cache记住的方法(因为这是一个昂贵的数据库调用)。与pytest-mock

该代码的简化版本是:

class User:

    def __init__(self, file):
        # load a file

    @lru_cache
    def get(self, user_id):
        # do expensive call

然后我正在测试:

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')

但是我遇到以下错误:

TypeError: unhashable type: '_ANY'

之所以会发生这种情况,是因为functools.lru_cache需要存储的密钥是​​可散列的,即已实现了方法__hash____cmp__

如何在模拟程序中模拟此类方法以使其正常工作?

我尝试过

user.__hash__.return_value = 'foo'

没有运气。

2 个答案:

答案 0 :(得分:0)

代替使用mocker.ANY(打算在断言中用作占位符的对象,该对象等于任何对象),我相信您想使用哨兵对象(例如mocker.sentinel.DATA) 。

这似乎可以通过快速测试来实现:

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)

答案 1 :(得分:0)

对于到达这里试图解决如何测试以lru_cachealru_cache装饰的功能的人们来说,答案是在每次测试之前先clear the cache

这可以如下进行:

def setup_function():
    """
    Avoid the `(a)lru_cache` causing tests with identical parameters to interfere
    with one another.
    """
    my_cached_function.cache_clear()