Files
claude-howto/zh/.github/TESTING.md
Luong NGUYEN 89e89d4aa3 feat(zh): add Chinese translations in zh/ directory
Add Chinese (Simplified) translations for all documentation, organized
under a dedicated zh/ directory that mirrors the English folder structure.

Co-authored-by: tanqingkuang <tanqingkuang@users.noreply.github.com>

Translations originally contributed by @tanqingkuang in #45.
Restructured from *-CN.md suffix pattern into zh/ directory to prevent
the EPUB builder (scripts/build_epub.py collect_folder_files) from
picking up Chinese files via glob("*.md") inside module folders.
2026-04-06 23:08:54 +02:00

342 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 测试指南
本文档说明 Claude How To 的测试基础设施。
## 概览
项目使用 GitHub Actions 在每次 push 和 pull request 时自动运行测试。测试覆盖:
- **单元测试**:使用 pytest 的 Python 测试
- **代码质量**:使用 Ruff 做 lint 和格式化
- **安全**:使用 Bandit 做漏洞扫描
- **类型检查**:使用 mypy 做静态类型分析
- **构建验证**EPUB 生成测试
## 在本地运行测试
### 前置条件
```bash
# 安装 uv快速 Python 包管理器)
pip install uv
# 或者在 macOS 上使用 Homebrew
brew install uv
```
### 配置环境
```bash
# 克隆仓库
git clone https://github.com/luongnv89/claude-howto.git
cd claude-howto
# 创建虚拟环境
uv venv
# 激活虚拟环境
source .venv/bin/activate # macOS/Linux
# 或者
.venv\Scripts\activate # Windows
# 安装开发依赖
uv pip install -r requirements-dev.txt
```
### 运行测试
```bash
# 运行所有单元测试
pytest scripts/tests/ -v
# 运行带覆盖率的测试
pytest scripts/tests/ -v --cov=scripts --cov-report=html
# 运行指定测试文件
pytest scripts/tests/test_build_epub.py -v
# 运行指定测试函数
pytest scripts/tests/test_build_epub.py::test_function_name -v
# 以 watch 模式运行测试(需要 pytest-watch
ptw scripts/tests/
```
### 运行 lint
```bash
# 检查代码格式
ruff format --check scripts/
# 自动修复格式问题
ruff format scripts/
# 运行 lint
ruff check scripts/
# 自动修复 lint 问题
ruff check --fix scripts/
```
### 运行安全扫描
```bash
# 运行 Bandit 安全扫描
bandit -c pyproject.toml -r scripts/ --exclude scripts/tests/
# 生成 JSON 报告
bandit -c pyproject.toml -r scripts/ --exclude scripts/tests/ -f json -o bandit-report.json
```
### 运行类型检查
```bash
# 使用 mypy 检查类型
mypy scripts/ --ignore-missing-imports --no-implicit-optional
```
## GitHub Actions 工作流
### 触发条件
- 推送到 `main``develop` 分支(当 `scripts` 有变更时)
-`main` 提交 Pull Request`scripts` 有变更时)
- 手动触发 workflow
### 作业
#### 1. 单元测试pytest
- **运行环境**Ubuntu latest
- **Python 版本**3.10、3.11、3.12
- **执行内容**
-`requirements-dev.txt` 安装依赖
- 运行 pytest 并生成覆盖率报告
- 将覆盖率上传到 Codecov
- 归档测试结果和 HTML 覆盖率报告
**结果**:如果任何测试失败,工作流失败(关键)
#### 2. 代码质量Ruff
- **运行环境**Ubuntu latest
- **Python 版本**3.11
- **执行内容**
- 使用 `ruff format` 检查格式
- 使用 `ruff check` 运行 lint
- 报告问题,但不会让整个工作流失败
**结果**:非阻塞(仅警告)
#### 3. 安全扫描Bandit
- **运行环境**Ubuntu latest
- **Python 版本**3.11
- **执行内容**
- 扫描安全漏洞
- 生成 JSON 报告
- 将报告作为 artifact 上传
**结果**:非阻塞(仅警告)
#### 4. 类型检查mypy
- **运行环境**Ubuntu latest
- **Python 版本**3.11
- **执行内容**
- 执行静态类型分析
- 报告类型不匹配
- 帮助尽早发现 bug
**结果**:非阻塞(仅警告)
#### 5. 构建 EPUB
- **运行环境**Ubuntu latest
- **依赖**pytest、lint、安全扫描都必须通过
- **执行内容**
- 使用 `scripts/build_epub.py` 构建 EPUB
- 验证 EPUB 是否成功生成
- 将 EPUB 作为 artifact 上传
**结果**:如果构建失败,工作流失败(关键)
#### 6. 总结
- **运行环境**Ubuntu latest
- **依赖**:所有其他作业
- **执行内容**
- 生成工作流总结
- 列出所有 artifacts
- 汇总总体状态
## 编写测试
### 测试结构
测试应放在 `scripts/tests/` 中,文件名形如 `test_*.py`
```python
# scripts/tests/test_example.py
import pytest
from scripts.example_module import some_function
def test_basic_functionality():
"""测试 some_function 是否正常工作。"""
result = some_function("input")
assert result == "expected_output"
def test_error_handling():
"""测试 some_function 是否能优雅处理错误。"""
with pytest.raises(ValueError):
some_function("invalid_input")
@pytest.mark.asyncio
async def test_async_function():
"""测试异步函数。"""
result = await async_function()
assert result is not None
```
### 测试最佳实践
- **使用有描述性的名称**:例如 `test_function_returns_correct_value()`
- **尽量每个测试只做一个断言**:更容易排查失败原因
- **使用 fixture** 复用初始化逻辑:见 `scripts/tests/conftest.py`
- **Mock 外部服务**:使用 `unittest.mock``pytest-mock`
- **测试边界情况**空输入、None 值、错误情况
- **保持测试快速**:避免 `sleep()` 和外部 I/O
- **使用 pytest 标记**:例如 `@pytest.mark.slow` 标记慢测试
### Fixtures
常用 fixture 定义在 `scripts/tests/conftest.py`
```python
# 在测试中使用 fixture
def test_something(tmp_path):
"""tmp_path fixture 提供临时目录。"""
test_file = tmp_path / "test.txt"
test_file.write_text("content")
assert test_file.read_text() == "content"
```
## 覆盖率报告
### 本地覆盖率
```bash
# 生成覆盖率报告
pytest scripts/tests/ --cov=scripts --cov-report=html
# 在浏览器中打开覆盖率报告
open htmlcov/index.html
```
### 覆盖率目标
- **最低覆盖率**80%
- **分支覆盖率**:启用
- **重点区域**:核心功能和错误路径
## Pre-commit Hooks
项目使用 pre-commit hooks 在每次提交前自动运行检查:
```bash
# 安装 pre-commit hooks
pre-commit install
# 手动运行 hooks
pre-commit run --all-files
# 跳过某次提交的 hooks不推荐
git commit --no-verify
```
`.pre-commit-config.yaml` 中配置的 hooks
- Ruff formatter
- Ruff linter
- Bandit security scanner
- YAML validation
- 文件大小检查
- 合并冲突检测
## 排障
### 本地测试通过,但 CI 失败
常见原因:
1. **Python 版本差异**CI 使用 3.10、3.11、3.12
2. **依赖缺失**:更新 `requirements-dev.txt`
3. **平台差异**:路径分隔符、环境变量
4. **测试不稳定**:依赖时序或执行顺序的测试
解决方案:
```bash
# 使用相同的 Python 版本测试
uv python install 3.10 3.11 3.12
# 使用干净环境测试
rm -rf .venv
uv venv
uv pip install -r requirements-dev.txt
pytest scripts/tests/
```
### Bandit 报告误报
某些安全警告可能是误报。可在 `pyproject.toml` 中配置:
```toml
[tool.bandit]
exclude_dirs = ["scripts/tests"]
skips = ["B101"] # 跳过 assert_used 警告
```
### 类型检查太严格
对特定文件放宽类型检查:
```python
# 放在文件顶部
# type: ignore
# 或者针对特定行
some_dynamic_code() # type: ignore
```
## 持续集成最佳实践
1. **保持测试快速**:每个测试最好在 1 秒内完成
2. **不要测试外部 API**:用 mock 替代外部服务
3. **测试要隔离**:每个测试都应独立
4. **断言要清晰**:写 `assert x == 5`,不要写 `assert x`
5. **处理异步测试**:使用 `@pytest.mark.asyncio`
6. **生成报告**:覆盖率、安全扫描、类型检查
## 资源
- [pytest Documentation](https://docs.pytest.org/)
- [Ruff Documentation](https://docs.astral.sh/ruff/)
- [Bandit Documentation](https://bandit.readthedocs.io/)
- [mypy Documentation](https://mypy.readthedocs.io/)
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
## 贡献测试
提交 PR 时:
1. **为新功能编写测试**
2. **本地运行测试**`pytest scripts/tests/ -v`
3. **检查覆盖率**`pytest scripts/tests/ --cov=scripts`
4. **运行 lint**`ruff check scripts/`
5. **安全扫描**`bandit -r scripts/ --exclude scripts/tests/`
6. **如果测试变化,更新文档**
所有 PR 都必须包含测试!🧪
---
如果你对测试有问题或疑问,请在 GitHub 上创建 issue 或 discussion。