Py.test修补模块内对象

时间:2014-12-15 06:27:09

标签: python unit-testing testing pytest

我有一个包裹:

- package/
  - __init__.py
  - cache.py
  - module1.py
  - module2.py
- tests/
  - test_module1.py
  - test_module2.py
  - conftest.py

module1module2都从cache.py导入:

from package.cache import cache

@cache()
def foo():
   ...

默认情况下,cache使用由dogpile.cache提供的基于文件的缓存,但是在运行测试时,我想使用基于内存的缓存来模拟cache,这也得到了dogpile.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)

正如您所看到的,我创建了一个夹具,其中使用monkeypatchcache替换为m_cache

然而,这不起作用,当我使用py.test运行测试时,他们仍在使用旧的基于文件的缓存。有什么不对吗?

2 个答案:

答案 0 :(得分:1)

导入模块时应用

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

答案 1 :(得分:0)

我最近遇到了类似的pytest和monkeypatching问题,我认为应该使用monkeypatch来解决。我试图将我的烧瓶应用程序中的缓存替换为内存缓存,以便我的缓存视图和其他东西不会意外地破坏真正的应用程序缓存键。

我发现的问题是,与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编辑,我需要一个明确设置所有这些属性的工具:

# 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

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

然而,它有效。

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

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

我的烧瓶应用程序正在使用Redis缓存,所以看到上面的内容告诉我它已经成功。