使用 lru_cache 装饰器测试功能

adr*_*ino 0 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
Run Code Online (Sandbox Code Playgroud)

然后我正在测试:

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

Run Code Online (Sandbox Code Playgroud)

但我收到以下错误:

TypeError: unhashable type: '_ANY'
Run Code Online (Sandbox Code Playgroud)

发生这种情况是因为functools.lru_cache需要存储的密钥是​​可散列的,即有一个方法__hash____cmp__实现。

我怎样才能在嘲笑者中嘲笑这些方法以使其工作?

我试过了

user.__hash__.return_value = 'foo'
Run Code Online (Sandbox Code Playgroud)

没有运气。

Lon*_*Rob 11

对于到达这里并试图弄清楚如何测试用lru_cache或修饰的函数的人来说alru_cache,答案是在每次测试之前清除缓存

这可以按如下方式完成:

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


Ant*_*ile 2

我相信您不想使用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)
Run Code Online (Sandbox Code Playgroud)