You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 00:35:35