Python Py.test修补模块内对象

Python Py.test修补模块内对象,python,unit-testing,testing,pytest,Python,Unit Testing,Testing,Pytest,我有一个包裹: - package/ - __init__.py - cache.py - module1.py - module2.py - tests/ - test_module1.py - test_module2.py - conftest.py module1和module2都从cache.py导入: from package.cache import cache @cache() def foo(): ... 默认情况下,cache使用的是提

我有一个包裹:

- package/
  - __init__.py
  - cache.py
  - module1.py
  - module2.py
- tests/
  - test_module1.py
  - test_module2.py
  - conftest.py
module1
module2
都从
cache.py
导入:

from package.cache import cache

@cache()
def foo():
   ...
默认情况下,
cache
使用的是提供的基于文件的缓存,但是在运行测试时,我希望使用同样受支持的基于内存的缓存来模拟
cache

以下是我想说的:

# conftest.py

import pytest

@pytest.fixture(autouse=True)
def patch_cache(monkeypatch):
    from dogpile.cache import make_region
    m_cache = make_region().configure('dogpile.cache.memory')
    monkeypatch.setattr('package.cache.cache', m_cache)
如您所见,我创建了一个fixture,其中使用
monkeypatch
cache
替换为
m\u cache


但是,这不起作用,当我使用
py.test
运行测试时,它们仍然使用旧的基于文件的缓存。有什么问题吗?

@cache()
是在导入模块时应用的,因为decorator是在模块的顶层调用的。如果在导入该模块后对其进行monkeypatch,则不会应用您的修补版本。

我最近在pytest和monkeypatch方面遇到了类似的问题,我认为应该通过使用
monkeypatch来解决。我试图将flask应用程序中的缓存换成内存中的缓存,这样缓存的视图和其他内容就不会意外地破坏真正的应用程序缓存键

我发现的问题是,就像
unittest.mock.patch
一样,我必须修补被修补的东西被导入和使用的位置,换句话说,调用站点

想象一下以下一组模块:

# package1/app1/module1.py

from flask_app import cache
cache.get("SOMEKEY")


# package1/app2/module1.py

from flask_app import cache
cache.get("SOMEKEY")


# package1/app2/module2.py

from package1.app2.module1 import cache
cache.get("SOMEKEY")
现在,在pytest中,为了保证所有这些不同版本的
cache
都已
monkeypatch
ed,我需要一个fixture来显式设置所有这些版本的属性:

# conftest.py
from werkzeug.contrib.cache import SimpleCache

@pytest.fixture(scope="function", autouse=True)
def safe_cache(request, monkeypatch):
    """
    Monkeypatch the cache so it doesn't clobber real keys.

    Clear after every test.
    """
    cache = SimpleCache()
    monkeypatch.setattr('package1.app1.module1.cache', cache)
    monkeypatch.setattr('package1.app2.module1.cache', cache)
    monkeypatch.setattr('package1.app2.module2.cache', cache)    

    def teardown():
        cache.clear()
    request.addfinalizer(teardown)

    return cache
这有点烦人,因为每次我编写一个导入缓存的新模块时,我还必须在monkeypatch这些缓存的夹具中对其进行monkeypatch

然而,这是可行的

当我在导入缓存的其中一个模块中设置断点并检查它使用的是什么时,我会看到以下内容:

ipdb> cache
<werkzeug.contrib.cache.SimpleCache object at 0x10d658ac8>
ipdb>缓存

我的flask应用程序使用的是Redis缓存,因此看到上面的内容,我就知道它是成功的。

我认为,在
pytest的魔力下,这在技术上是不正确的。实际上,您可以修改模块级别的内容,因为fixture在解析测试和导入应用程序代码之前运行:这既奇怪又令人惊讶。我认为这里的问题是在导入站点进行修补。