Pytest monkeypatch Mock跨测试用例泄漏问题求助
问题根源分析
你遇到的核心问题是模块级单例导致的Mock实例复用:handler.py中模块级别的r = Redis(...)在第一次导入时就会创建Redis实例,后续测试导入handler时不会重新执行这段初始化代码,导致所有测试复用同一个FakeRedis实例(第一个测试创建的)。即使你在fixture中调用flushall(),第二个测试用的依然是第一个测试的FakeRedis实例,而非新创建的实例,因此残留数据会导致测试失败。
解决方案
方案1:修改handler模块(推荐,更健壮)
将Redis实例的创建逻辑移到函数内部,避免模块级单例:
# handler.py import os from redis import Redis def lambda_handler(event, context): """Lambda Handler""" host = os.environ["REDIS_HOSTNAME"] r = Redis(host=host, db=0) # 每次调用函数时创建独立实例 for key, value in event.items(): r.set(key, value) keys = r.keys() return keys
这样每个测试调用lambda_handler时,都会基于当前mock的Redis创建新实例,自然不会出现数据泄漏。
方案2:测试中重新加载handler模块
如果无法修改handler,可在每个测试前重新加载模块,强制重新执行模块级初始化代码:
import pytest import redis import importlib import handler from fakeredis import FakeRedis @pytest.fixture() def hostname(): return "a fake host" @pytest.fixture() def fake_redis(hostname): return FakeRedis(host=hostname, db=0) @pytest.fixture(autouse=True) def mock_redis(monkeypatch, fake_redis, hostname): def _redis(*args, **kwargs): return fake_redis monkeypatch.setattr(redis, "Redis", _redis) monkeypatch.setattr(redis, "StrictRedis", _redis) monkeypatch.setenv("REDIS_HOSTNAME", hostname) @pytest.fixture(autouse=True) def reload_handler(): # 每个测试前重新加载handler,重置模块级实例 importlib.reload(handler) def test_cache_is_set(): result = handler.lambda_handler({"a_key": "value"}, {}) assert len(result) == 1 def test_cache_is_empty(): result = handler.lambda_handler({}, {}) assert len(result) == 0
方案3:直接替换handler模块的r实例
在fixture中直接替换handler模块已有的r实例为当前测试的FakeRedis:
import pytest import redis import handler from fakeredis import FakeRedis @pytest.fixture() def hostname(): return "a fake host" @pytest.fixture() def fake_redis(hostname): return FakeRedis(host=hostname, db=0) @pytest.fixture(autouse=True) def mock_redis(monkeypatch, fake_redis, hostname): def _redis(*args, **kwargs): return fake_redis monkeypatch.setattr(redis, "Redis", _redis) monkeypatch.setattr(redis, "StrictRedis", _redis) monkeypatch.setenv("REDIS_HOSTNAME", hostname) # 强制替换handler模块中的r实例为当前测试的fake_redis monkeypatch.setattr(handler, "r", fake_redis) def test_cache_is_set(): result = handler.lambda_handler({"a_key": "value"}, {}) assert len(result) == 1 def test_cache_is_empty(): result = handler.lambda_handler({}, {}) assert len(result) == 0
内容的提问来源于stack exchange,提问作者CaptainDriftwood
相关产品推荐
相关产品推荐

