709 lines
15 KiB
Markdown
709 lines
15 KiB
Markdown
|
|
# 测试规范
|
|||
|
|
|
|||
|
|
## 一、测试概述
|
|||
|
|
|
|||
|
|
### 1.1 测试目标
|
|||
|
|
|
|||
|
|
确保 aide 程序的所有功能正确、稳定、可靠,满足设计要求。
|
|||
|
|
|
|||
|
|
### 1.2 测试范围
|
|||
|
|
|
|||
|
|
- 单元测试:核心模块和函数
|
|||
|
|
- 集成测试:命令完整流程
|
|||
|
|
- 跨平台测试:Linux、macOS、Windows
|
|||
|
|
- 性能测试:执行时间和资源占用
|
|||
|
|
|
|||
|
|
### 1.3 测试工具
|
|||
|
|
|
|||
|
|
- **pytest**:测试框架
|
|||
|
|
- **pytest-cov**:代码覆盖率
|
|||
|
|
- **pytest-mock**:模拟和打桩
|
|||
|
|
- **pytest-timeout**:超时控制
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、测试结构
|
|||
|
|
|
|||
|
|
### 2.1 目录结构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
tests/
|
|||
|
|
├── __init__.py
|
|||
|
|
├── conftest.py # pytest 配置和 fixtures
|
|||
|
|
├── unit/ # 单元测试
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── test_output.py # 输出模块测试
|
|||
|
|
│ ├── test_config.py # 配置模块测试
|
|||
|
|
│ └── test_validators.py # 验证函数测试
|
|||
|
|
├── integration/ # 集成测试
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── test_init.py # aide init 测试
|
|||
|
|
│ ├── test_env.py # aide env 测试
|
|||
|
|
│ └── test_config_cmd.py # aide config 测试
|
|||
|
|
└── fixtures/ # 测试数据
|
|||
|
|
├── sample_config.toml
|
|||
|
|
└── sample_gitignore
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 命名规范
|
|||
|
|
|
|||
|
|
- 测试文件:`test_<module>.py`
|
|||
|
|
- 测试类:`Test<Feature>`
|
|||
|
|
- 测试函数:`test_<scenario>`
|
|||
|
|
|
|||
|
|
**示例**:
|
|||
|
|
```python
|
|||
|
|
# test_config.py
|
|||
|
|
class TestConfig:
|
|||
|
|
def test_load_success(self):
|
|||
|
|
"""测试成功加载配置"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def test_load_file_not_found(self):
|
|||
|
|
"""测试配置文件不存在"""
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、单元测试
|
|||
|
|
|
|||
|
|
### 3.1 core/output.py 测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tests/unit/test_output.py
|
|||
|
|
import pytest
|
|||
|
|
from core.output import ok, warn, err, info
|
|||
|
|
|
|||
|
|
def test_ok_simple(capsys):
|
|||
|
|
"""测试简单成功输出"""
|
|||
|
|
ok("操作成功")
|
|||
|
|
|
|||
|
|
captured = capsys.readouterr()
|
|||
|
|
assert "✓ 操作成功" in captured.out
|
|||
|
|
|
|||
|
|
def test_ok_with_details(capsys):
|
|||
|
|
"""测试带详细信息的成功输出"""
|
|||
|
|
ok("操作成功", ["详细信息1", "详细信息2"])
|
|||
|
|
|
|||
|
|
captured = capsys.readouterr()
|
|||
|
|
assert "✓ 操作成功" in captured.out
|
|||
|
|
assert " 详细信息1" in captured.out
|
|||
|
|
assert " 详细信息2" in captured.out
|
|||
|
|
|
|||
|
|
def test_warn(capsys):
|
|||
|
|
"""测试警告输出"""
|
|||
|
|
warn("这是警告")
|
|||
|
|
|
|||
|
|
captured = capsys.readouterr()
|
|||
|
|
assert "⚠ 这是警告" in captured.out
|
|||
|
|
|
|||
|
|
def test_err(capsys):
|
|||
|
|
"""测试错误输出"""
|
|||
|
|
err("这是错误", ["建议: 检查配置"])
|
|||
|
|
|
|||
|
|
captured = capsys.readouterr()
|
|||
|
|
assert "✗ 这是错误" in captured.out
|
|||
|
|
assert " 建议: 检查配置" in captured.out
|
|||
|
|
|
|||
|
|
def test_info(capsys):
|
|||
|
|
"""测试信息输出"""
|
|||
|
|
info("正在处理...")
|
|||
|
|
|
|||
|
|
captured = capsys.readouterr()
|
|||
|
|
assert "→ 正在处理..." in captured.out
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 core/config.py 测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tests/unit/test_config.py
|
|||
|
|
import pytest
|
|||
|
|
from pathlib import Path
|
|||
|
|
from core.config import Config, get_config_value, set_config_value
|
|||
|
|
|
|||
|
|
def test_get_config_value():
|
|||
|
|
"""测试获取配置值"""
|
|||
|
|
config = {
|
|||
|
|
"task": {
|
|||
|
|
"source": "task-now.md"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
assert get_config_value(config, "task.source") == "task-now.md"
|
|||
|
|
assert get_config_value(config, "task.spec", "default") == "default"
|
|||
|
|
|
|||
|
|
def test_set_config_value():
|
|||
|
|
"""测试设置配置值"""
|
|||
|
|
config = {"task": {}}
|
|||
|
|
|
|||
|
|
set_config_value(config, "task.source", "new-task.md")
|
|||
|
|
assert config["task"]["source"] == "new-task.md"
|
|||
|
|
|
|||
|
|
def test_config_load(tmp_path):
|
|||
|
|
"""测试加载配置"""
|
|||
|
|
# 创建测试配置文件
|
|||
|
|
config_dir = tmp_path / ".aide"
|
|||
|
|
config_dir.mkdir()
|
|||
|
|
config_path = config_dir / "config.toml"
|
|||
|
|
config_path.write_text('[task]\nsource = "test.md"\n')
|
|||
|
|
|
|||
|
|
# 加载配置
|
|||
|
|
config = Config(tmp_path)
|
|||
|
|
config.load()
|
|||
|
|
|
|||
|
|
assert config.get("task.source") == "test.md"
|
|||
|
|
|
|||
|
|
def test_config_load_not_found(tmp_path):
|
|||
|
|
"""测试配置文件不存在"""
|
|||
|
|
config = Config(tmp_path)
|
|||
|
|
|
|||
|
|
with pytest.raises(FileNotFoundError):
|
|||
|
|
config.load()
|
|||
|
|
|
|||
|
|
def test_config_save(tmp_path):
|
|||
|
|
"""测试保存配置"""
|
|||
|
|
# 创建配置
|
|||
|
|
config_dir = tmp_path / ".aide"
|
|||
|
|
config_dir.mkdir()
|
|||
|
|
|
|||
|
|
config = Config(tmp_path)
|
|||
|
|
config._config = {"task": {"source": "test.md"}}
|
|||
|
|
config.save()
|
|||
|
|
|
|||
|
|
# 验证文件已创建
|
|||
|
|
config_path = tmp_path / ".aide" / "config.toml"
|
|||
|
|
assert config_path.exists()
|
|||
|
|
|
|||
|
|
# 验证内容
|
|||
|
|
content = config_path.read_text()
|
|||
|
|
assert "task" in content
|
|||
|
|
assert "test.md" in content
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 utils/validators.py 测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tests/unit/test_validators.py
|
|||
|
|
import pytest
|
|||
|
|
from utils.validators import is_valid_version_spec, validate_config
|
|||
|
|
|
|||
|
|
def test_is_valid_version_spec():
|
|||
|
|
"""测试版本规格验证"""
|
|||
|
|
assert is_valid_version_spec(">=3.10") == True
|
|||
|
|
assert is_valid_version_spec("3.12") == True
|
|||
|
|
assert is_valid_version_spec(">=3.10,<4.0") == True
|
|||
|
|
assert is_valid_version_spec("invalid") == False
|
|||
|
|
|
|||
|
|
def test_validate_config():
|
|||
|
|
"""测试配置验证"""
|
|||
|
|
# 有效配置
|
|||
|
|
valid_config = {
|
|||
|
|
"task": {"source": "task.md", "spec": "spec.md"},
|
|||
|
|
"env": {"python": {"version": ">=3.10"}},
|
|||
|
|
"output": {"language": "zh-CN"}
|
|||
|
|
}
|
|||
|
|
errors = validate_config(valid_config)
|
|||
|
|
assert len(errors) == 0
|
|||
|
|
|
|||
|
|
# 缺少必需项
|
|||
|
|
invalid_config = {"task": {}}
|
|||
|
|
errors = validate_config(invalid_config)
|
|||
|
|
assert len(errors) > 0
|
|||
|
|
assert any("task.source" in e for e in errors)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、集成测试
|
|||
|
|
|
|||
|
|
### 4.1 aide init 测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tests/integration/test_init.py
|
|||
|
|
import pytest
|
|||
|
|
from pathlib import Path
|
|||
|
|
from commands.init import cmd_init
|
|||
|
|
|
|||
|
|
def test_init_success(tmp_path, monkeypatch):
|
|||
|
|
"""测试初始化成功"""
|
|||
|
|
monkeypatch.chdir(tmp_path)
|
|||
|
|
|
|||
|
|
result = cmd_init([])
|
|||
|
|
|
|||
|
|
assert result == 0
|
|||
|
|
assert (tmp_path / ".aide").exists()
|
|||
|
|
assert (tmp_path / ".aide" / "config.toml").exists()
|
|||
|
|
assert (tmp_path / ".gitignore").exists()
|
|||
|
|
|
|||
|
|
def test_init_idempotent(tmp_path, monkeypatch):
|
|||
|
|
"""测试幂等性"""
|
|||
|
|
monkeypatch.chdir(tmp_path)
|
|||
|
|
|
|||
|
|
# 第一次初始化
|
|||
|
|
result1 = cmd_init([])
|
|||
|
|
assert result1 == 0
|
|||
|
|
|
|||
|
|
# 读取配置内容
|
|||
|
|
config_path = tmp_path / ".aide" / "config.toml"
|
|||
|
|
content1 = config_path.read_text()
|
|||
|
|
|
|||
|
|
# 第二次初始化
|
|||
|
|
result2 = cmd_init([])
|
|||
|
|
assert result2 == 0
|
|||
|
|
|
|||
|
|
# 验证配置未改变
|
|||
|
|
content2 = config_path.read_text()
|
|||
|
|
assert content1 == content2
|
|||
|
|
|
|||
|
|
def test_init_permission_error(tmp_path, monkeypatch):
|
|||
|
|
"""测试权限错误"""
|
|||
|
|
monkeypatch.chdir(tmp_path)
|
|||
|
|
|
|||
|
|
# 设置只读权限
|
|||
|
|
tmp_path.chmod(0o444)
|
|||
|
|
|
|||
|
|
result = cmd_init([])
|
|||
|
|
|
|||
|
|
# 恢复权限
|
|||
|
|
tmp_path.chmod(0o755)
|
|||
|
|
|
|||
|
|
assert result != 0
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 aide env 测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tests/integration/test_env.py
|
|||
|
|
import pytest
|
|||
|
|
from commands.env import cmd_env, env_ensure_runtime, env_ensure_project
|
|||
|
|
|
|||
|
|
def test_env_ensure_runtime_success():
|
|||
|
|
"""测试运行时环境检测成功"""
|
|||
|
|
result = env_ensure_runtime()
|
|||
|
|
assert result == 0
|
|||
|
|
|
|||
|
|
def test_env_ensure_project_success(tmp_path, monkeypatch):
|
|||
|
|
"""测试项目环境检测成功"""
|
|||
|
|
monkeypatch.chdir(tmp_path)
|
|||
|
|
|
|||
|
|
# 初始化项目
|
|||
|
|
from commands.init import cmd_init
|
|||
|
|
cmd_init([])
|
|||
|
|
|
|||
|
|
# 检测环境
|
|||
|
|
result = env_ensure_project()
|
|||
|
|
assert result == 0
|
|||
|
|
|
|||
|
|
def test_env_ensure_project_no_config(tmp_path, monkeypatch):
|
|||
|
|
"""测试配置文件不存在"""
|
|||
|
|
monkeypatch.chdir(tmp_path)
|
|||
|
|
|
|||
|
|
result = env_ensure_project()
|
|||
|
|
assert result == 4
|
|||
|
|
|
|||
|
|
def test_env_ensure_create_venv(tmp_path, monkeypatch):
|
|||
|
|
"""测试自动创建虚拟环境"""
|
|||
|
|
monkeypatch.chdir(tmp_path)
|
|||
|
|
|
|||
|
|
# 初始化项目
|
|||
|
|
from commands.init import cmd_init
|
|||
|
|
cmd_init([])
|
|||
|
|
|
|||
|
|
# 检测环境(应该自动创建虚拟环境)
|
|||
|
|
result = env_ensure_project()
|
|||
|
|
assert result == 0
|
|||
|
|
|
|||
|
|
# 验证虚拟环境已创建
|
|||
|
|
assert (tmp_path / ".venv").exists()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 aide config 测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tests/integration/test_config_cmd.py
|
|||
|
|
import pytest
|
|||
|
|
from commands.config_cmd import cmd_config, config_get, config_set
|
|||
|
|
|
|||
|
|
def test_config_get_success(tmp_path, monkeypatch, capsys):
|
|||
|
|
"""测试获取配置成功"""
|
|||
|
|
monkeypatch.chdir(tmp_path)
|
|||
|
|
|
|||
|
|
# 初始化
|
|||
|
|
from commands.init import cmd_init
|
|||
|
|
cmd_init([])
|
|||
|
|
|
|||
|
|
# 获取配置
|
|||
|
|
result = config_get("task.source")
|
|||
|
|
assert result == 0
|
|||
|
|
|
|||
|
|
captured = capsys.readouterr()
|
|||
|
|
assert "task.source" in captured.out
|
|||
|
|
assert "task-now.md" in captured.out
|
|||
|
|
|
|||
|
|
def test_config_set_success(tmp_path, monkeypatch):
|
|||
|
|
"""测试设置配置成功"""
|
|||
|
|
monkeypatch.chdir(tmp_path)
|
|||
|
|
|
|||
|
|
# 初始化
|
|||
|
|
from commands.init import cmd_init
|
|||
|
|
cmd_init([])
|
|||
|
|
|
|||
|
|
# 设置配置
|
|||
|
|
result = config_set("task.source", "new-task.md")
|
|||
|
|
assert result == 0
|
|||
|
|
|
|||
|
|
# 验证配置已更新
|
|||
|
|
result = config_get("task.source")
|
|||
|
|
assert result == 0
|
|||
|
|
|
|||
|
|
def test_config_cmd_no_args(capsys):
|
|||
|
|
"""测试无参数"""
|
|||
|
|
result = cmd_config([])
|
|||
|
|
assert result == 2
|
|||
|
|
|
|||
|
|
captured = capsys.readouterr()
|
|||
|
|
assert "缺少子命令" in captured.out
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、跨平台测试
|
|||
|
|
|
|||
|
|
### 5.1 路径处理测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def test_path_handling_cross_platform(tmp_path):
|
|||
|
|
"""测试跨平台路径处理"""
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
# 使用 pathlib 确保跨平台兼容
|
|||
|
|
aide_dir = tmp_path / ".aide"
|
|||
|
|
config_path = aide_dir / "config.toml"
|
|||
|
|
|
|||
|
|
aide_dir.mkdir()
|
|||
|
|
config_path.write_text("test")
|
|||
|
|
|
|||
|
|
assert config_path.exists()
|
|||
|
|
assert config_path.is_file()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.2 命令执行测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
@pytest.mark.skipif(sys.platform == "win32", reason="Unix only")
|
|||
|
|
def test_unix_specific():
|
|||
|
|
"""Unix 特定测试"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
|
|||
|
|
def test_windows_specific():
|
|||
|
|
"""Windows 特定测试"""
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、性能测试
|
|||
|
|
|
|||
|
|
### 6.1 执行时间测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
import time
|
|||
|
|
|
|||
|
|
def test_init_performance(tmp_path, monkeypatch):
|
|||
|
|
"""测试初始化性能"""
|
|||
|
|
monkeypatch.chdir(tmp_path)
|
|||
|
|
|
|||
|
|
start = time.time()
|
|||
|
|
result = cmd_init([])
|
|||
|
|
elapsed = time.time() - start
|
|||
|
|
|
|||
|
|
assert result == 0
|
|||
|
|
assert elapsed < 0.2 # 应该在 200ms 内完成
|
|||
|
|
|
|||
|
|
def test_config_get_performance(tmp_path, monkeypatch):
|
|||
|
|
"""测试配置读取性能"""
|
|||
|
|
monkeypatch.chdir(tmp_path)
|
|||
|
|
|
|||
|
|
# 初始化
|
|||
|
|
cmd_init([])
|
|||
|
|
|
|||
|
|
# 测试性能
|
|||
|
|
start = time.time()
|
|||
|
|
result = config_get("task.source")
|
|||
|
|
elapsed = time.time() - start
|
|||
|
|
|
|||
|
|
assert result == 0
|
|||
|
|
assert elapsed < 0.1 # 应该在 100ms 内完成
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 内存占用测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
import psutil
|
|||
|
|
import os
|
|||
|
|
|
|||
|
|
def test_memory_usage():
|
|||
|
|
"""测试内存占用"""
|
|||
|
|
process = psutil.Process(os.getpid())
|
|||
|
|
mem_before = process.memory_info().rss / 1024 / 1024 # MB
|
|||
|
|
|
|||
|
|
# 执行操作
|
|||
|
|
cmd_init([])
|
|||
|
|
|
|||
|
|
mem_after = process.memory_info().rss / 1024 / 1024 # MB
|
|||
|
|
mem_used = mem_after - mem_before
|
|||
|
|
|
|||
|
|
assert mem_used < 50 # 应该小于 50MB
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、测试覆盖率
|
|||
|
|
|
|||
|
|
### 7.1 覆盖率要求
|
|||
|
|
|
|||
|
|
- **核心模块**:≥ 80%
|
|||
|
|
- **命令模块**:≥ 80%
|
|||
|
|
- **工具模块**:≥ 70%
|
|||
|
|
- **整体**:≥ 75%
|
|||
|
|
|
|||
|
|
### 7.2 运行覆盖率测试
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 运行测试并生成覆盖率报告
|
|||
|
|
pytest --cov=src --cov-report=html --cov-report=term
|
|||
|
|
|
|||
|
|
# 查看覆盖率报告
|
|||
|
|
open htmlcov/index.html
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.3 覆盖率配置
|
|||
|
|
|
|||
|
|
```ini
|
|||
|
|
# .coveragerc
|
|||
|
|
[run]
|
|||
|
|
source = src
|
|||
|
|
omit =
|
|||
|
|
*/tests/*
|
|||
|
|
*/venv/*
|
|||
|
|
*/__pycache__/*
|
|||
|
|
|
|||
|
|
[report]
|
|||
|
|
exclude_lines =
|
|||
|
|
pragma: no cover
|
|||
|
|
def __repr__
|
|||
|
|
raise AssertionError
|
|||
|
|
raise NotImplementedError
|
|||
|
|
if __name__ == .__main__.:
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 八、测试 Fixtures
|
|||
|
|
|
|||
|
|
### 8.1 conftest.py
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tests/conftest.py
|
|||
|
|
import pytest
|
|||
|
|
from pathlib import Path
|
|||
|
|
import shutil
|
|||
|
|
|
|||
|
|
@pytest.fixture
|
|||
|
|
def temp_project(tmp_path):
|
|||
|
|
"""创建临时项目目录"""
|
|||
|
|
project_dir = tmp_path / "test_project"
|
|||
|
|
project_dir.mkdir()
|
|||
|
|
return project_dir
|
|||
|
|
|
|||
|
|
@pytest.fixture
|
|||
|
|
def initialized_project(temp_project, monkeypatch):
|
|||
|
|
"""创建已初始化的项目"""
|
|||
|
|
monkeypatch.chdir(temp_project)
|
|||
|
|
from commands.init import cmd_init
|
|||
|
|
cmd_init([])
|
|||
|
|
return temp_project
|
|||
|
|
|
|||
|
|
@pytest.fixture
|
|||
|
|
def sample_config():
|
|||
|
|
"""示例配置"""
|
|||
|
|
return {
|
|||
|
|
"task": {
|
|||
|
|
"source": "task-now.md",
|
|||
|
|
"spec": "task-spec.md"
|
|||
|
|
},
|
|||
|
|
"env": {
|
|||
|
|
"python": {
|
|||
|
|
"version": ">=3.10",
|
|||
|
|
"venv": ".venv"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 九、持续集成
|
|||
|
|
|
|||
|
|
### 9.1 GitHub Actions 配置
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
# .github/workflows/test.yml
|
|||
|
|
name: Tests
|
|||
|
|
|
|||
|
|
on: [push, pull_request]
|
|||
|
|
|
|||
|
|
jobs:
|
|||
|
|
test:
|
|||
|
|
runs-on: ${{ matrix.os }}
|
|||
|
|
strategy:
|
|||
|
|
matrix:
|
|||
|
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|||
|
|
python-version: ['3.10', '3.11', '3.12']
|
|||
|
|
|
|||
|
|
steps:
|
|||
|
|
- uses: actions/checkout@v3
|
|||
|
|
|
|||
|
|
- name: Set up Python
|
|||
|
|
uses: actions/setup-python@v4
|
|||
|
|
with:
|
|||
|
|
python-version: ${{ matrix.python-version }}
|
|||
|
|
|
|||
|
|
- name: Install dependencies
|
|||
|
|
run: |
|
|||
|
|
python -m pip install --upgrade pip
|
|||
|
|
pip install pytest pytest-cov pytest-mock
|
|||
|
|
pip install tomli tomli-w
|
|||
|
|
|
|||
|
|
- name: Run tests
|
|||
|
|
run: |
|
|||
|
|
pytest --cov=src --cov-report=xml
|
|||
|
|
|
|||
|
|
- name: Upload coverage
|
|||
|
|
uses: codecov/codecov-action@v3
|
|||
|
|
with:
|
|||
|
|
file: ./coverage.xml
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十、测试最佳实践
|
|||
|
|
|
|||
|
|
### 10.1 测试原则
|
|||
|
|
|
|||
|
|
1. **独立性**:每个测试独立运行,不依赖其他测试
|
|||
|
|
2. **可重复性**:多次运行结果一致
|
|||
|
|
3. **清晰性**:测试意图明确,易于理解
|
|||
|
|
4. **快速性**:测试执行快速,及时反馈
|
|||
|
|
|
|||
|
|
### 10.2 测试模式
|
|||
|
|
|
|||
|
|
**AAA 模式**(Arrange-Act-Assert):
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def test_example():
|
|||
|
|
# Arrange:准备测试数据
|
|||
|
|
config = {"task": {"source": "test.md"}}
|
|||
|
|
|
|||
|
|
# Act:执行操作
|
|||
|
|
result = get_config_value(config, "task.source")
|
|||
|
|
|
|||
|
|
# Assert:验证结果
|
|||
|
|
assert result == "test.md"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 10.3 Mock 使用
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from unittest.mock import Mock, patch
|
|||
|
|
|
|||
|
|
def test_with_mock(monkeypatch):
|
|||
|
|
"""使用 mock 测试"""
|
|||
|
|
# Mock 函数
|
|||
|
|
mock_func = Mock(return_value=True)
|
|||
|
|
monkeypatch.setattr("module.function", mock_func)
|
|||
|
|
|
|||
|
|
# 执行测试
|
|||
|
|
result = some_function()
|
|||
|
|
|
|||
|
|
# 验证 mock 被调用
|
|||
|
|
mock_func.assert_called_once()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十一、测试检查清单
|
|||
|
|
|
|||
|
|
### 11.1 单元测试
|
|||
|
|
|
|||
|
|
- [ ] core/output.py 所有函数
|
|||
|
|
- [ ] core/config.py 所有函数
|
|||
|
|
- [ ] utils/validators.py 所有函数
|
|||
|
|
- [ ] 边界条件测试
|
|||
|
|
- [ ] 错误路径测试
|
|||
|
|
|
|||
|
|
### 11.2 集成测试
|
|||
|
|
|
|||
|
|
- [ ] aide init 完整流程
|
|||
|
|
- [ ] aide env ensure --runtime
|
|||
|
|
- [ ] aide env ensure
|
|||
|
|
- [ ] aide config get
|
|||
|
|
- [ ] aide config set
|
|||
|
|
- [ ] 命令组合测试
|
|||
|
|
|
|||
|
|
### 11.3 跨平台测试
|
|||
|
|
|
|||
|
|
- [ ] Linux 测试通过
|
|||
|
|
- [ ] macOS 测试通过
|
|||
|
|
- [ ] Windows 测试通过
|
|||
|
|
- [ ] 路径处理正确
|
|||
|
|
|
|||
|
|
### 11.4 性能测试
|
|||
|
|
|
|||
|
|
- [ ] 执行时间符合要求
|
|||
|
|
- [ ] 内存占用符合要求
|
|||
|
|
- [ ] 无内存泄漏
|
|||
|
|
|
|||
|
|
### 11.5 覆盖率
|
|||
|
|
|
|||
|
|
- [ ] 核心模块 ≥ 80%
|
|||
|
|
- [ ] 命令模块 ≥ 80%
|
|||
|
|
- [ ] 整体 ≥ 75%
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十二、总结
|
|||
|
|
|
|||
|
|
### 12.1 核心要点
|
|||
|
|
|
|||
|
|
1. 完整的测试覆盖(单元、集成、跨平台)
|
|||
|
|
2. 明确的覆盖率要求
|
|||
|
|
3. 持续集成自动化
|
|||
|
|
4. 遵循测试最佳实践
|
|||
|
|
|
|||
|
|
### 12.2 运行测试
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 运行所有测试
|
|||
|
|
pytest
|
|||
|
|
|
|||
|
|
# 运行特定测试
|
|||
|
|
pytest tests/unit/test_config.py
|
|||
|
|
|
|||
|
|
# 运行带覆盖率的测试
|
|||
|
|
pytest --cov=src
|
|||
|
|
|
|||
|
|
# 运行性能测试
|
|||
|
|
pytest -m performance
|
|||
|
|
|
|||
|
|
# 运行跨平台测试
|
|||
|
|
pytest -m cross_platform
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**版本**:v1.0
|
|||
|
|
**更新日期**:2025-12-13
|