49 lines
3.5 KiB
Markdown
49 lines
3.5 KiB
Markdown
# 架构重构机会
|
||
|
||
本文档记录了在开发过程中发现的、有价值的但因当前优先级或工作量而暂未实施的架构重构机会。旨在为未来的代码质量提升和迭代开发提供清晰的路线图。
|
||
|
||
## 1. 改进 `APITestOrchestrator` 的依赖注入和生命周期管理
|
||
|
||
### 当前问题与"不优雅"的根源
|
||
|
||
在为测试用例引入 `SchemaProvider` 作为核心依赖时,我们遇到了一个典型的 **对象生命周期与依赖注入时序问题**。
|
||
|
||
1. **理想的设计** 是由框架(`APITestOrchestrator`)在初始化时创建并持有一个全局唯一的 `SchemaProvider` 实例,然后在创建测试用例时,将这个实例 **注入** 进去。
|
||
2. **现实的障碍** 是 `SchemaProvider` 的创建依赖于 `global_api_spec`(即解析后的API规范文件),而 `global_api_spec` 本身是在 `APITestOrchestrator` 实例化很久之后,在 `run_tests_from_yapi/swagger` 等方法内部才被加载和创建的。
|
||
3. **导致的结果** 是我们无法在 `APITestOrchestrator` 的 `__init__` 方法中优雅地创建 `SchemaProvider`,这导致了 `AttributeError`。
|
||
|
||
我们当前采用的临时方案是让每个测试用例自己在 `__init__` 中创建 `SchemaProvider` 实例。这虽然解决了功能问题,但存在代码重复,并且违背了依赖注入的最佳实践。
|
||
|
||
### 待实施的重构方案
|
||
|
||
#### 方案A: 内部逻辑提炼 (中期优化)
|
||
|
||
这是我们讨论过的、侵入性较小的优化方案。
|
||
|
||
1. 在 `APITestOrchestrator` 中创建一个新的私有方法,例如 `_initialize_spec_dependent_services(self, parsed_spec)`。
|
||
2. 此方法负责获取 `parsed_spec`,设置 `self.global_api_spec`,并创建所有依赖它的服务(如 `SchemaProvider`),将实例存放在 `self` 的属性中。
|
||
3. 在 `run_tests_from_yapi` 和 `run_tests_from_swagger` 的开头,调用这个新的私有方法。
|
||
4. 改造 `BaseAPITestCase`,使其能够接收注入的 `schema_provider` 实例。
|
||
|
||
**优点**: 实现简单,风险小,能有效减少测试用例中的代码重复。
|
||
|
||
#### 方案B: 彻底分离业务阶段 (长期目标)
|
||
|
||
这是更理想、更彻底的重构方案,它将 `APITestOrchestrator` 的功能进行明确的阶段划分。
|
||
|
||
1. **重构 `APITestOrchestrator` 的公共API**,将其从一个大而全的 `run_tests_from_...` 方法,拆分为多个独立的、职责单一的公共方法,例如:
|
||
* `load_spec(file_path: str) -> ParsedAPISpec`: 只负责加载和解析文件,返回一个解析后的对象。
|
||
* `prepare_execution(parsed_spec: ParsedAPISpec)`: 接收解析后的对象,用它来初始化所有依赖的服务,如 `SchemaProvider`,并准备好待测试的端点列表。
|
||
* `execute() -> TestSummary`: 执行所有准备好的测试,并返回最终的摘要。
|
||
|
||
2. **调整调用流程**: `run_api_tests.py` 中的 `main` 函数也需要相应调整,以适配这种分阶段的调用方式。
|
||
|
||
**优点**:
|
||
* **完全符合单一职责原则**:每个方法只做一件事。
|
||
* **生命周期清晰**:数据和依赖的生命周期管理变得非常清晰、可控。
|
||
* **高度可测试**:可以单独对 `load_spec` 或 `prepare_execution` 进行单元测试。
|
||
* **更灵活**: 未来可以支持更复杂的场景,比如加载多个API规范文件后合并测试。
|
||
|
||
### 重构收益
|
||
|
||
完成上述任一方案(特别是方案B),将使得测试框架的核心代码更加健壮、可维护和可扩展,为未来添加更复杂的功能(如测试依赖、多文件聚合测试等)打下坚实的基础。 |