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

使用Pytest测试Flask应用时gcloud库抛出DefaultCredentialsError的解决方法

解决Flask单元测试中Google客户端的凭证错误问题

你遇到的问题本质是:初始化容器时会自动创建bigquery.Client和SecretManagerServiceClient的单例实例,触发Google SDK的凭证检查,但测试环境不想存放真实凭证。之前的mock失败是因为patch的路径不对,或者没有利用dependency_injector本身的依赖替换能力。下面是几个可行的解决方案:

1. 正确使用mock patch路径

mock的关键是patch被代码实际引用的位置,而不是类的定义位置。你的容器代码里直接导入了bigquery.Client和secretmanager.SecretManagerServiceClient,所以要patch容器模块中的这些引用,而不是google.cloud下的原始类。

假设你的容器代码在app/core/containers.py,测试代码应该这么写:

from unittest import mock
from app.core.containers import Core

def test_ping():
    with mock.patch('app.core.containers.bigquery.Client') as mock_bq, \
         mock.patch('app.core.containers.secretmanager.SecretManagerServiceClient') as mock_secret:
        # 不需要返回None,默认mock实例就够了
        app = create_app()
        response = app.test_client().get("/api/v1/health")
        assert b"ok" in response.data

2. 利用dependency_injector的override功能(更优雅)

dependency_injector本身提供了覆盖依赖的机制,不需要用mock.patch,直接替换容器中的提供者:

from unittest.mock import Mock
from app.container import Container
from dependency_injector import providers

def test_ping():
    # 创建mock客户端实例
    mock_bq_client = Mock()
    mock_secret_client = Mock()

    # 临时覆盖Core容器中的客户端提供者
    with Container.core.override(
        bigquery_client=providers.Singleton(lambda: mock_bq_client),
        secretmanager_client=providers.Singleton(lambda: mock_secret_client)
    ):
        app = create_app()
        response = app.test_client().get("/api/v1/health")
        assert b"ok" in response.data

3. 给容器添加测试模式开关

修改核心容器,通过配置参数控制是否使用mock客户端,避免测试时创建真实实例:

from dependency_injector import containers, providers
from google.cloud import bigquery, secretmanager
from unittest.mock import Mock

class Core(containers.DeclarativeContainer):
    # 添加一个依赖参数,控制是否启用mock
    test_mode = providers.Dependency(default=False)

    bigquery_client = providers.Singleton(
        lambda self: Mock() if self.test_mode() else bigquery.Client(),
        depends_on=[test_mode]
    )

    secretmanager_client = providers.Singleton(
        lambda self: Mock() if self.test_mode() else secretmanager.SecretManagerServiceClient(),
        depends_on=[test_mode]
    )

    # 其他仓库定义不变...

测试时传入test_mode=True:

def test_ping():
    # 创建容器时开启测试模式
    container = Container(core=providers.Container(Core, test_mode=True))
    app = Flask(__name__)
    app.container = container
    container.core.init_resources()
    
    response = app.test_client().get("/api/v1/health")
    assert b"ok" in response.data

4. 创建测试专用容器

继承原核心容器,替换所有Google客户端为mock,测试时直接使用这个容器:

from unittest.mock import Mock
from app.core.containers import Core, Container

class TestCore(Core):
    # 替换为mock实例
    bigquery_client = providers.Singleton(Mock)
    secretmanager_client = providers.Singleton(Mock)

class TestContainer(Container):
    core = providers.Container(TestCore)

def test_ping():
    # 使用测试容器创建应用
    app = Flask(__name__)
    app.container = TestContainer()
    app.container.core.init_resources()
    
    response = app.test_client().get("/api/v1/health")
    assert b"ok" in response.data

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 23:33:20