# 测试框架使用指南 ## 概述 项目已配置 **pytest** 测试框架,相比你之前的手动测试方法,有以下优势: ### ✅ 改进点 | 旧方法 (Jupyter Notebook) | 新方法 (pytest) | |-------------------------|----------------| | 手动运行每个测试用例 | 自动发现和运行所有测试 | | 手动读取和对比文件 | 自动化断言和差异报告 | | 难以定位失败原因 | 清晰的错误堆栈和 diff | | 无法批量运行 | 支持参数化和并行测试 | | 无覆盖率统计 | 自动生成覆盖率报告 | ## 快速开始 ### 1. 运行所有测试 ```bash python -m pytest ``` ### 2. 运行特定测试文件 ```bash python -m pytest tests/test_playlist_merge.py -v ``` ### 3. 在 VS Code 中运行 - 按 `Ctrl+Shift+P` - 输入 "Run Task" - 选择 "运行所有测试" 或其他测试任务 ## 测试文件说明 ### 已创建的测试文件 ``` tests/ ├── __init__.py # 包初始化 ├── conftest.py # pytest fixtures 和配置 ├── test_playlist_merge.py # 播放列表合并测试 └── README.md # 详细测试指南 ``` ### 测试用例覆盖 `test_playlist_merge.py` 包含: 1. **基础功能测试** (`TestPlaylistMergeBasics`) - `test_load_paths_removes_comments` - 测试路径加载 - `test_save_paths_adds_header` - 测试文件保存 - `test_empty_playlist_merge` - 测试空播放列表合并 2. **本地优先测试** (`TestPlaylistMergeLocalPriority`) - 参数化测试 case1-4 的本地优先合并 3. **远程优先测试** (`TestPlaylistMergeRemotePriority`) - 参数化测试 case1-4 的远程优先合并 4. **冲突检测测试** (`TestConflictDetection`) - 测试冲突识别和解决 ## 常用命令 ### 基础运行 ```bash # 运行所有测试 pytest # 详细输出 pytest -v # 显示 print 输出 pytest -s # 只运行特定测试 pytest tests/test_playlist_merge.py::TestPlaylistMergeBasics::test_load_paths_removes_comments ``` ### 测试筛选 ```bash # 运行特定 case pytest -k "case_num-1" # 运行包含特定关键字的测试 pytest -k "local_priority" # 运行标记的测试 pytest -m unit ``` ### 调试和重试 ```bash # 失败时进入调试器 pytest --pdb # 只运行上次失败的测试 pytest --lf # 先运行失败的测试 pytest --ff # 遇到第一个失败就停止 pytest -x ``` ### 覆盖率报告 ```bash # 生成覆盖率报告 pytest --cov=app --cov-report=html # 在浏览器中查看 # 打开 htmlcov/index.html # 终端中显示覆盖率 pytest --cov=app --cov-report=term ``` ## 编写新测试 ### 1. 创建测试文件 在 `tests/` 目录下创建 `test_.py` ### 2. 编写测试类和函数 ```python import pytest class TestMyFeature: """测试我的功能""" def test_basic_case(self): """测试基本用例""" result = my_function() assert result == expected_value @pytest.mark.parametrize("input,expected", [ (1, 2), (2, 4), (3, 6), ]) def test_multiple_cases(self, input, expected): """参数化测试多个用例""" assert my_function(input) == expected ``` ### 3. 使用 fixtures ```python @pytest.fixture def sample_data(): """提供测试数据""" return {"key": "value"} def test_with_fixture(sample_data): assert sample_data["key"] == "value" ``` ## 与旧测试方法的对比 ### 旧方法 (test.ipynb) ```python # 手动循环和对比 for i in range(len(test_playlists[1])): with open(test_playlists[1][i], 'r', encoding='utf-8') as f1, \ open(target_playlists[i], 'r', encoding='utf-8') as f2: content1 = f1.read() content2 = f2.read() # 手动处理和对比... if content1 == content2: print(f"Test case {i+1} passed.") else: print(f"Test case {i+1} failed.") ``` ### 新方法 (pytest) ```python @pytest.mark.parametrize("case_num", [1, 2, 3, 4]) def test_merge_local_priority(case_num, tmp_path): """自动运行所有用例,失败时显示详细 diff""" # 加载输入 base_text = load_file(f"case{case_num}.m3u") # ... 执行测试 result = merge_playlists(base_text, local_text, remote_text) # 自动断言和差异报告 assert_playlists_equal(actual_file, expected_file) ``` ## 持续集成 可以将测试集成到 CI/CD 流程: ```yaml # .github/workflows/test.yml (示例) name: Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 - name: Install dependencies run: pip install -r requirements.txt - name: Run tests run: pytest --cov=app ``` ## 最佳实践 1. **测试命名** - 使用清晰描述性的名称 2. **独立性** - 每个测试应该独立运行 3. **快速** - 单元测试应该快速执行 4. **明确** - 一个测试只测一个功能点 5. **维护** - 定期更新测试用例 ## 故障排除 ### pytest 找不到 ```bash python -m pip install pytest pytest-cov ``` ### 导入错误 确保项目根目录在 Python 路径中: ```python import sys sys.path.insert(0, str(Path(__file__).parent.parent)) ``` ### 测试发现失败 检查 `pytest.ini` 配置和文件命名是否符合规范。 ## 下一步 - [ ] 为其他模块添加测试 (如 `plex_client.py`, `local_playlist.py`) - [ ] 添加集成测试 - [ ] 配置 CI/CD 自动运行测试 - [ ] 设置测试覆盖率目标 (如 >80%) ## 参考资料 - [pytest 官方文档](https://docs.pytest.org/) - [pytest-cov 文档](https://pytest-cov.readthedocs.io/) - 项目内测试: `tests/README.md`