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

求助:如何通过pytest向init.py传入mock boto3 client?调用真实实例问题

问题原因

你的核心问题出在模块导入时机与mock生效时机不匹配:

  • init.py中的params = {'token': get_token()}、job_1()、job_2(params)属于模块级代码,当你在测试中(或pytest执行时)导入init模块时,这些代码会立刻执行,而此时你的mock_boto3_client fixture还未被激活(fixture在测试函数运行阶段才会生效)。
  • 另外,你测试用例中创建的secret名称是my-test-secret,但实际代码调用的是my-secret/my-token,即使mock生效也会找不到对应secret。
解决方案

要解决这个问题,需要从两个方面调整:

  1. 重构init.py,避免模块级别的立即执行代码,将业务逻辑封装到函数中,由外部控制执行时机。
  2. 确保mock在代码执行前就生效,同时修正secret名称不匹配的问题。

步骤1:重构init.py

把模块级执行的代码放到函数里,只有当脚本直接运行时才执行:

from helpers.token_helper import get_token
from my_jobs.jobs import job_1, job_2

def run_jobs():
    params = {'token': get_token()}
    job_1()
    job_2(params)

# 只有直接运行该脚本时才执行,导入时不触发
if __name__ == "__main__":
    run_jobs()

步骤2:修改测试用例

使用autouse=True的fixture提前激活moto mock,确保在任何代码执行前mock就生效,同时修正secret名称与代码保持一致:

import pytest
import boto3
import moto
from my_jobs.init import run_jobs
from my_jobs.jobs import job_1

@pytest.fixture(scope="session", autouse=True)
def mock_secretsmanager():
    with moto.mock_secretsmanager():
        client = boto3.client("secretsmanager", region_name="us-east-1")
        # 与代码中调用的secret名称保持一致
        secret_name = "my-secret/my-token"
        secret_value = "my-test-secret-value"
        client.create_secret(Name=secret_name, SecretString=secret_value)
        yield client

def test_job_1():
    response = job_1()
    assert response == 'yay'

def test_run_jobs(mock_secretsmanager):
    # 此时调用run_jobs,get_token会使用mock的secretsmanager
    run_jobs()
    # 可根据job_2的实际行为添加断言,比如验证参数是否正确传递

可选优化:让aws_helper更易测试

可以修改aws_helper.py,允许传入自定义的boto3客户端,这样测试时可以直接注入mock客户端,无需依赖moto:

import boto3

def get_secret(secret_name, client=None):
    # 如果没有传入client,才创建默认的
    if not client:
        client = boto3.client("secretsmanager", region_name="us-east-1")
    try:
        response = client.get_secret_value(SecretId=secret_name)
        return response["SecretString"]
    except Exception as e:
        print(e)
        raise e

这样在测试token_helper.py时,可以直接传入mock客户端:

from unittest.mock import Mock
from helpers.token_helper import get_token

def test_get_token_with_secret():
    mock_client = Mock()
    mock_client.get_secret_value.return_value = {"SecretString": "test-token"}
    
    from helpers import token_helper
    # 替换token_helper里的get_secret为带mock客户端的版本
    def mock_get_secret(name):
        return token_helper.get_secret(name, client=mock_client)
    token_helper.get_secret = mock_get_secret
    
    token = get_token()
    assert token == "test-token"

内容的提问来源于stack exchange,提问作者walkingwithataco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:45:15