首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在pytest中模拟模块级函数

在pytest中模拟模块级函数
EN

Stack Overflow用户
提问于 2019-06-26 08:42:23
回答 1查看 1.6K关注 0票数 1

我有一个有装饰器的函数。装饰器接受参数,参数的值是从另一个函数调用派生的。

example.py

代码语言:javascript
复制
from cachetools import cached
from cachetools import TTLCache

from other import get_value


@cached(cache=TTLCache(maxsize=1, ttl=get_value('cache_ttl')))
def my_func():
    return 'result'

other.py

代码语言:javascript
复制
def get_value(key):
    data = {
        'cache_ttl': 10,
    }
    # Let's assume here we launch a shuttle to the space too.
    return data[key]

我想模拟一下对get_value()的调用。我在我的测试中使用了以下内容:

example_test.py

代码语言:javascript
复制
import mock
import pytest

from example import my_func


@pytest.fixture
def mock_get_value():
    with mock.patch(
        "example.get_value",
        autospec=True,
    ) as _mock:
        yield _mock


def test_my_func(mock_get_value):
    assert my_func() == 'result'

这里我要向test_my_func注入mock_get_value。但是,因为我的装饰器是在第一次导入时调用的,所以get_value()会立即被调用。你知道有没有办法在使用pytest导入模块之前模拟对get_value()的调用?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-26 09:20:34

在测试函数中的with中移动from example import my_func。还要在它真正来自的地方修补它,other.get_value。这可能就是它所需要的。

Python在sys.modules中缓存模块,因此模块级代码(如函数定义)只在第一次从任何地方导入时运行。如果这不是第一次,您可以使用importlib.reload()或通过在sys.modules中删除适当的键并再次导入来强制重新导入。

请注意,重新导入模块可能会有副作用,您可能还希望在运行测试后再次导入该模块,以避免干扰其他测试。如果另一个模块正在使用重新导入的模块中定义的对象,这些对象不会消失,并且可能不会按预期的方式进行更新。例如,重新导入模块可能会创建本应为单例的第二个实例。

一种更健壮的方法是将原始导入的模块对象保存在其他地方,从sys.modules中删除,在测试期间使用修补后的版本重新导入,然后在测试结束后将原始导入放回sys.modules中。您可以通过在sys.modules上的patch.dict()上下文中导入来实现这一点。

代码语言:javascript
复制
import mock
import sys

import pytest

@pytest.fixture
def mock_get_value():
    with mock.patch(
        "other.get_value",
        autospec=True,
    ) as _mock, mock.patch.dict("sys.modules"):
        sys.modules.pop("example", None)
        yield _mock


def test_my_func(mock_get_value):
    from example import my_func
    assert my_func() == 'result'

另一种可能是在测试中对原始函数调用装饰器。如果装饰器使用functools.wraps()/functools.update_wrapper(),那么原始函数应该作为__wrapped__属性可用。这可能不可用,这取决于装饰器是如何实现的。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56763710

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档