如何在模块级pytest fixture中正确使用mock_secretsmanager?
解决模块级pytest fixture中mock AWS Secrets Manager的问题
问题现象
在模块级pytest fixture中使用@mock_secretsmanager装饰器创建模拟Secrets Manager秘钥并设置环境变量时,运行测试出现以下错误:
botocore.errorfactory.ResourceNotFoundException: An error occurred (ResourceNotFoundException) when calling the GetSecretValue operation: Secrets Manager can't find the specified secret.
错误代码示例:
@pytest.fixture(scope="module") def monkeypatch_module(): # 处理pytest monkeypatch模块级作用域的问题 from _pytest.monkeypatch import MonkeyPatch mpatch = MonkeyPatch() yield mpatch mpatch.undo() @pytest.fixture(scope="module") @mock_secretsmanager def setup_stuff(monkeypatch_module): secret_name = "test_mock_secret01" sm_client = boto3.client("secretsmanager", region_name="us-east-1") sm_client.create_secret( Name=secret_name, SecretString='{"username":"mockuser","password":"mockpass"}', ) # 设置模块级环境变量 monkeypatch_module.setenv("MY_VAR", "sldkfjsdf") @pytest.mark.unittest def test__mytest(setup_stuff): secret_name = "test_mock_secret01" my_method_that_gets_the_secret(secret_name)
临时方案是将setup改为函数在每个测试中调用,但会重复执行模拟操作,不符合模块级fixture一次性执行的需求。
错误原因
@mock_secretsmanager装饰器仅在被装饰的fixture函数执行期间生效,当fixture执行完成后(无yield时直接结束),mock上下文会立即关闭。测试函数运行时,mock已经失效,无法找到之前创建的模拟秘钥。
正确实现方案
使用mock_secretsmanager的上下文管理器形式,配合fixture的yield语法,让mock在整个模块测试周期内保持活跃:
@pytest.fixture(scope="module") def monkeypatch_module(): from _pytest.monkeypatch import MonkeyPatch mpatch = MonkeyPatch() yield mpatch mpatch.undo() @pytest.fixture(scope="module") def setup_stuff(monkeypatch_module): secret_name = "test_mock_secret01" # 启动mock上下文并保持至所有模块测试完成 with mock_secretsmanager(): # 创建模拟秘钥 sm_client = boto3.client("secretsmanager", region_name="us-east-1") sm_client.create_secret( Name=secret_name, SecretString='{"username":"mockuser","password":"mockpass"}', ) # 设置模块级环境变量 monkeypatch_module.setenv("MY_VAR", "sldkfjsdf") # 让出执行权,让模块内的测试函数在mock上下文中运行 yield # 退出with块后自动关闭mock @pytest.mark.unittest def test__mytest(setup_stuff): secret_name = "test_mock_secret01" my_method_that_gets_the_secret(secret_name)
关键说明
- 通过
with mock_secretsmanager():手动管理mock的生命周期,确保在模块内所有测试运行期间mock始终生效。 - fixture中的
yield语句会暂停fixture执行,直到模块内所有测试完成后才继续执行with块后续的关闭逻辑,完美匹配模块级作用域的需求。 - 模块级环境变量通过
monkeypatch_module设置,会在所有模块测试完成后统一撤销。
内容的提问来源于stack exchange,提问作者red888
相关产品推荐
相关产品推荐

