使用Python dependency_injection库测试用例时依赖未定义问题排查
问题分析与解决方案
问题遗漏点
报错的核心是UseCases容器未正确关联测试适配器的依赖,具体可能是以下几点:
- 测试fixture中仅初始化了UseCases,但未将TestAdapters注入到UseCases的
adapters依赖项中,导致UseCases.adapters.respository找不到绑定实例。 - 容器初始化顺序错误:必须先完成TestAdapters的初始化与配置,再初始化UseCases,否则UseCases无法解析依赖。
- 测试环境下
get_adapter函数未正确返回TestAdapters,导致UseCases仍尝试依赖未初始化的生产环境Adapters。
修复示例(基于你的容器结构)
假设你的容器定义如下:
from dependency_injector import containers, providers class Adapters(containers.DeclarativeContainer): repository = providers.Factory(ProductionRepository) class TestAdapters(containers.DeclarativeContainer): repository = providers.Factory(InMemoryRepository) class UseCases(containers.DeclarativeContainer): adapters = providers.DependenciesContainer() user_service = providers.Factory(UserService, repository=adapters.repository) def get_adapter(env): return TestAdapters() if env == "test" else Adapters()
对应的pytest fixture需补充依赖绑定逻辑:
import pytest from your_module import UseCases, get_adapter @pytest.fixture(scope="function") def test_adapters(): return get_adapter("test") @pytest.fixture(scope="function") def use_cases(test_adapters): # 将TestAdapters绑定到UseCases的adapters依赖 use_cases_container = UseCases(adapters=test_adapters) # 初始化所有依赖资源 use_cases_container.init_resources() return use_cases_container
更优实现方式
无需单独定义TestAdapters容器,利用dependency_injector的override机制直接覆盖生产环境依赖,更简洁且符合库的设计意图:
1. 生产容器定义
from dependency_injector import containers, providers class Adapters(containers.DeclarativeContainer): repository = providers.Factory(ProductionRepository) class UseCases(containers.DeclarativeContainer): adapters = providers.DependenciesContainer() user_service = providers.Factory(UserService, repository=adapters.repository) # 全局初始化生产容器 adapters = Adapters() use_cases = UseCases(adapters=adapters)
2. 测试fixture实现
import pytest from your_module import adapters, use_cases, InMemoryRepository @pytest.fixture(scope="function") def setup_test_adapters(): # 覆盖生产环境的repository为内存实现 override = adapters.repository.override(InMemoryRepository) yield # 测试结束后恢复生产依赖,避免影响其他用例 override.reset() @pytest.fixture(scope="function") def test_use_cases(setup_test_adapters): return use_cases
3. 进阶优化:自动绑定测试依赖
使用autouse=True让所有测试用例自动使用测试适配器,无需显式引用fixture:
@pytest.fixture(scope="function", autouse=True) def auto_setup_test_adapters(): override = adapters.repository.override(InMemoryRepository) yield override.reset()
内容的提问来源于stack exchange,提问作者Tâmer Cuba
相关产品推荐
相关产品推荐

