
# 测试方案

## 1. 测试目标
- 单测覆盖率 ≥ 90%，CI 红线
- 所有子命令在 Windows / macOS / Linux 真实 `uv` 环境可跑通
- 测速模块网络异常 100% 被捕获，程序不崩溃
- 并发场景下读写 `uv.toml` 无竞态损坏

---

## 2. 测试分层

| 层级 | 技术 | 粒度 | 触发时机 |
|----|------|------|----------|
| 单元 | pytest + pytest-asyncio | 函数级 | pre-commit & CI |
| 集成 | typer CliRunner | 命令级 | CI |
| 端到端 | GitHub Actions Matrix | 真机 `uv` | Release PR |
| 性能 | pytest-benchmark | 测速 ≤1 s | 每周定时 CRON |

---

## 3. 单元测试目录
```
tests/
├── unit/
│   ├── test_config.py        # uv.toml 读写、备份、还原
│   ├── test_mirror.py        # 内置+自定义源合并、重名检测
│   ├── test_speedtest.py     # 异步下载、异常超时、缓存
│   └── test_models.py        # pydantic 校验、URL 规范化
├── integration/
│   ├── test_cli_list.py
│   ├── test_cli_use.py
│   ├── test_cli_test.py
│   └── test_cli_reset.py
├── e2e/
│   └── test_real_uv.py       # 真实安装 uv 后验证索引生效
└── conftest.py               # 共享 fixture
```

---

## 4. 关键 fixture & 工具
```python
# conftest.py
@pytest.fixture(scope="session")
def temp_uv_home(tmp_path_factory):
    """隔离 XDG_CONFIG_HOME，避免污染开发者机器"""
    return tmp_path_factory.mktemp("uv_home")

@pytest.fixture
def mock_uv_toml(temp_uv_home) -> Path:
    toml = temp_uv_home / "uv" / "uv.toml"
    toml.parent.mkdir(exist_ok=True)
    toml.write_text("[uv]\nindex_url = \"https://pypi.org/simple\"")
    return toml

@pytest.fixture
def mock_mirror_server(aiohttp_server):
    """返回 200 与 404 两种场景，用于测速"""
    async def handler(request):
        return web.Response(body=b"x"*102400)
    app = web.Application()
    app.router.add_get("/simple/requests/", handler)
    return await aiohttp_server(app)
```

---

## 5. 测试场景举例

| 场景 | 断言 |
|------|------|
| `uvm use tsinghua` | `uv.toml` 中 `index_url` 被改写，且备份文件 `uv.toml.bak` 生成 |
| 镜像名重复 | `uvm add tsinghua xxx` 返回 exit_code=1，stderr 提示已存在 |
| 测速 3 个镜像 1 个超时 | 输出表格仅 2 条，返回码 0，日志记录 TimeoutError |
| 并发 10 进程同时 `uvm use` | 文件内容仍合法 toml，无截断 |
| Windows 路径带空格 | `platformdirs` 解析正常，配置写入成功 |

---

## 6. 覆盖率与质量门
```toml
# pyproject.toml
[tool.coverage.run]
source = ["uvm"]
omit = ["*/tests/*"]

[tool.coverage.report]
fail_under = 90
```

CI 步骤：
```yaml
- run: pytest --cov=uvm --cov-report=xml --cov-fail-under=90
- uses: codecov/codecov-action@v4
```

---

## 7. 端到端矩阵（GitHub Actions）
```yaml
strategy:
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    python: ["3.8", "3.11", "3.12"]
    uv: ["0.2.3", "latest"]
steps:
  - uses: actions/setup-python@v5
  - run: curl -LsSf https://astral.sh/uv/install.sh | sh
  - run: pip install .
  - run: uvm test  # 确保真机网络下测速通过
```

---

## 8. 性能基准
```python
# tests/perf/test_speed.py
def test_speed_benchmark(benchmark):
    from uvm.core.speedtest import probe
    result = benchmark(probe, Mirror(name="tsinghua", url="https://pypi.tuna.tsinghua.edu.cn/simple"))
    assert result < 0.8  # 秒
```
> 在 CI 中仅作软性警告，不影响合并；Release 前需通过。

---

## 9. 安全与异常注入
- 使用 `pytest-socket` 禁止非预期外网访问（UT 阶段）
- 通过 `tox` 启闭网络，确保离线场景下 `uvm list` 仍可用（读取内置源）
- 利用 `chaos-http-proxy` 随机延迟/丢包，验证测速稳定性

---

## 10. 发布前检查单（Review Template）
- [ ] 单元测试全部绿
- [ ] 覆盖率报告 90%+ 已上传
- [ ] E2E 矩阵三系统三 Python 版本绿
- [ ] `uvm use` 切换后 `uv pip install requests` 实际走新镜像（抓包或 `-v` 验证）
- [ ] 手工 `make chaos` 网络抖动 10 次无崩溃
- [ ] CHANGELOG 已更新

---
