使用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
相关产品推荐
相关产品推荐

