通用测试代码结构规范 - Cursor Rules
通用测试代码结构规范 - Cursor Rules
🎯 适用范围
本规范适用于所有Python项目的测试代码编写,与具体项目无关。
📋 核心原则
1. 路径配置(必须遵守)
# 每个测试文件开头必须包含以下路径设置代码
import sys
from pathlib import Path# 方法1: 基于测试文件位置自动计算项目根目录
PROJECT_ROOT = Path(__file__).parent.parent  # 如果测试文件在 tests/ 目录下
# PROJECT_ROOT = Path(__file__).parent.parent.parent  # 如果测试文件在 tests/unit/ 等子目录下# 方法2: 向上查找包含特定文件的目录(推荐)
def find_project_root(marker_files=['setup.py', 'pyproject.toml', 'requirements.txt', '.git']):current = Path(__file__).parentfor parent in [current] + list(current.parents):if any((parent / marker).exists() for marker in marker_files):return parentreturn current.parent  # 回退方案PROJECT_ROOT = find_project_root()
sys.path.insert(0, str(PROJECT_ROOT))
2. 统一配置管理(强烈推荐)
# tests/config.py - 测试专用配置文件
import sys
from pathlib import Path# 项目根目录设置
PROJECT_ROOT = Path(__file__).parent.parent
sys.path.insert(0, str(PROJECT_ROOT))# 测试环境配置
class TestConfig:"""测试环境配置"""# 路径配置PROJECT_ROOT = PROJECT_ROOTTEST_ROOT = Path(__file__).parentTEST_DATA_DIR = TEST_ROOT / "fixtures" / "sample_data"# 数据库配置TEST_DATABASE_PATH = TEST_ROOT / "test_database.db"# 导入并扩展项目配置def __init__(self):try:from config import config as project_config# 继承项目配置for attr in dir(project_config):if not attr.startswith('_'):setattr(self, attr, getattr(project_config, attr))# 覆盖测试专用配置self.DATABASE_PATH = str(self.TEST_DATABASE_PATH)except ImportError:# 提供基本配置作为回退self.setup_basic_config()def setup_basic_config(self):"""设置基本配置"""self.DATABASE_PATH = str(self.TEST_DATABASE_PATH)# 其他必要的基本配置...config = TestConfig()
3. 标准测试文件模板
# -*- coding: utf-8 -*-
"""
[功能模块]测试测试目标: [具体测试目标]
测试范围: [测试覆盖的功能范围]  
测试类型: [单元测试/集成测试/性能测试]
依赖组件: [列出依赖的主要组件]
最后更新: [YYYY-MM-DD]使用方法:python test_[功能名].pypytest test_[功能名].py -v预期结果:- [预期结果1]- [预期结果2]
"""# 1. 标准库导入
import asyncio
import logging
import sys
from pathlib import Path
from typing import Dict, List, Any, Optional# 2. 路径配置(必须在项目导入之前)
from tests.config import config  # 使用统一配置
# 或者直接设置路径(如果没有统一配置)
# PROJECT_ROOT = Path(__file__).parent.parent
# sys.path.insert(0, str(PROJECT_ROOT))# 3. 第三方库导入
import pytest  # 如果使用pytest# 4. 项目模块导入
from [项目模块] import [需要的类]# 5. 日志配置
logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)class Test[功能名]:"""[功能名]测试类"""def __init__(self):self.logger = logging.getLogger(self.__class__.__name__)# 初始化测试组件async def setup(self):"""测试设置"""# 初始化资源passasync def test_[具体功能](self):"""测试[具体功能]测试步骤:1. [准备步骤]2. [执行步骤] 3. [验证步骤]预期结果:- [具体预期]"""try:# Given - 准备测试数据# When - 执行被测试的功能# Then - 验证结果assert True  # 替换为实际断言except Exception as e:self.logger.error(f"测试失败: {e}", exc_info=True)raiseasync def cleanup(self):"""测试清理"""# 清理资源passasync def main():"""主函数 - 支持直接运行"""print("🧪 [功能名]测试")print("=" * 60)tester = Test[功能名]()try:await tester.setup()await tester.test_[具体功能]()print("✅ 测试通过")except Exception as e:print(f"❌ 测试失败: {e}")finally:await tester.cleanup()if __name__ == "__main__":asyncio.run(main())
📁 目录结构规范
项目根目录/
├── tests/                        # 测试根目录
│   ├── __init__.py              # 测试包初始化
│   ├── config.py                # 测试配置(必须)
│   ├── conftest.py              # pytest配置
│   ├── unit/                    # 单元测试
│   │   ├── __init__.py
│   │   └── test_*.py
│   ├── integration/             # 集成测试
│   │   ├── __init__.py
│   │   └── test_*.py
│   ├── performance/             # 性能测试
│   │   ├── __init__.py
│   │   └── test_*_performance.py
│   ├── fixtures/                # 测试数据
│   │   ├── __init__.py
│   │   ├── sample_data/
│   │   ├── mock_objects/
│   │   └── expected_results/
│   └── utils/                   # 测试工具
│       ├── __init__.py
│       └── test_helpers.py
├── src/                         # 源代码目录
├── config.py                    # 项目配置
├── requirements.txt             # 依赖文件
└── setup.py                     # 安装配置
🏷️ 命名规范
文件命名
test_[模块名]_[功能].py- 单元测试test_[系统功能].py- 集成测试test_[功能]_performance.py- 性能测试test_[功能]_manual.py- 手动测试
方法命名
def test_[动作]_[预期结果]_[条件](self):"""测试方法命名规范"""pass# 示例:
def test_create_user_success_with_valid_data(self):
def test_login_failure_with_invalid_password(self):
def test_process_large_file_timeout_after_30_seconds(self):
🔧 最佳实践
1. 导入顺序
# 1. 标准库
import os
import sys
from pathlib import Path# 2. 路径配置(必须在项目导入前)
from tests.config import config# 3. 第三方库
import pytest
import requests# 4. 项目模块
from myproject.module import MyClass
2. 异常处理
async def test_function_with_error_handling(self):"""带错误处理的测试方法"""try:# 测试逻辑result = await some_async_function()assert result is not Noneexcept Exception as e:self.logger.error(f"测试执行失败: {e}", exc_info=True)raise  # 重新抛出异常以便pytest捕获
3. 资源管理
class TestWithResources:"""需要资源管理的测试类"""async def setup(self):"""设置资源"""self.db_connection = await create_db_connection()self.temp_files = []async def cleanup(self):"""清理资源"""if hasattr(self, 'db_connection'):await self.db_connection.close()for temp_file in getattr(self, 'temp_files', []):if temp_file.exists():temp_file.unlink()
4. 测试数据管理
def load_test_data(filename: str) -> Any:"""加载测试数据的通用函数"""from tests.config import configdata_path = config.TEST_DATA_DIR / filenameif data_path.suffix == '.json':import jsonwith open(data_path, 'r', encoding='utf-8') as f:return json.load(f)elif data_path.suffix == '.txt':with open(data_path, 'r', encoding='utf-8') as f:return f.read()else:return str(data_path)
⚠️ 关键注意事项
1. 路径问题解决
# ❌ 错误方式 - 容易出现ModuleNotFoundError
from config import config# ✅ 正确方式 - 先设置路径再导入
from tests.config import config  # 配置文件已处理路径# ✅ 或者手动设置路径
PROJECT_ROOT = Path(__file__).parent.parent
sys.path.insert(0, str(PROJECT_ROOT))
from config import config
2. 配置隔离
# 测试配置应该与生产配置隔离
class TestConfig:def __init__(self):# 继承生产配置from config import config as prod_configself.__dict__.update(prod_config.__dict__)# 覆盖测试专用配置self.DATABASE_PATH = "test_database.db"self.DEBUG = True
3. 异步测试支持
# 支持pytest异步测试
@pytest.mark.asyncio
async def test_async_function():result = await async_function()assert result is not None# 支持直接运行异步测试
if __name__ == "__main__":asyncio.run(main())
📊 检查清单
在编写测试代码时,请确保:
- 包含正确的路径配置代码
 - 使用统一的测试配置文件
 - 文件和方法命名符合规范
 - 包含完整的文档字符串
 - 有适当的资源管理(setup/cleanup)
 - 异常处理完善
 - 支持直接运行和pytest运行
 - 测试数据与生产数据隔离
 - 日志配置合理
 - 断言信息清晰明确
 
🚀 快速开始
- 复制测试配置模板到 
tests/config.py - 根据项目调整配置参数
 - 使用测试文件模板创建新测试
 - 运行测试验证配置正确
 
