Skip to content

Commit 3f3e9f0

Browse files
committed
[feature]A testing framework based on pytest that supports multi-level testing, platform tagging, performance data collection, and Allure report generation.
1 parent 7c8c9a3 commit 3f3e9f0

File tree

12 files changed

+878
-0
lines changed

12 files changed

+878
-0
lines changed

test/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
reports/
2+
dataset/
3+
logs/
4+
*__pycache__/
5+
.*
6+
start.bat
7+
!.gitignore

test/README.md

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# UCM Pytest Testing Framework
2+
3+
A pytest-based testing framework that supports multi-level testing, platform tagging, performance data collection, and Allure report generation.
4+
[Chinese Documentation](README_zh.md)
5+
## Framework Features
6+
7+
- [x] 🏗️ **Multi-level Testing**: Unit(0) → Smoke(1) → Regression(2) → Release(3)
8+
- [x] 🏷️ **Flexible Tagging**: Supports feature tags and platform tags
9+
- [ ] 📊 **Data Collection**: Integrates InfluxDB performance data push
10+
- [ ] 📋 **Beautiful Reports**: Allure test report integration
11+
- [ ] 🔧 **Convenient Tools**: Rich testing tools and common methods
12+
13+
## Test Level Definitions
14+
15+
| Level | Name | Description | Execution Timing |
16+
|-------|------|-------------|------------------|
17+
| 0 | Unit | Unit tests | Each code commit |
18+
| 1 | Smoke | Smoke tests | Build verification |
19+
| 2 | Regression | Regression tests | Before version release |
20+
| 3 | Release | Release tests | Production environment verification |
21+
22+
## Directory Structure
23+
24+
```
25+
project/
26+
├── tests/
27+
│ ├── config.yaml # Testing framework configuration file
28+
│ ├── conftest.py # pytest configuration and fixtures, main entry point
29+
│ ├── common/ # Common utility library
30+
│ │ ├── __init__.py
31+
│ │ ├── config_utils.py # Configuration file reading utility
32+
│ │ ├── influxdb_utils.py # InfluxDB writing utility
33+
│ │ ├── allure_utils.py # Allure report utility
34+
│ ├── suites/ # Test case directory
35+
│ │ ├── unit/ # Unit tests (stage 0)
36+
│ │ ├── smoke/ # Smoke tests (stage 1)
37+
│ │ ├── regression/ # Regression tests (stage 2)
38+
│ │ └── release/ # Release tests (stage 3)
39+
├── requirements.txt # Dependencies
40+
├── pytest.ini # pytest configuration
41+
└── README.md # User guide
42+
```
43+
44+
## Test Case Standards
45+
46+
### Basic Structure
47+
48+
```python
49+
import pytest
50+
from tests.common.influxdb_utils import push_to_influx
51+
from tests.common.test_utils import setup_test_env
52+
53+
class TestExample:
54+
"""Test example class"""
55+
56+
@pytest.mark.stage(2)
57+
@pytest.mark.feature("accuracy")
58+
def test_calculation_accuracy(self):
59+
"""Test calculation accuracy"""
60+
# Arrange
61+
input_data = 1 + 1
62+
63+
# Act
64+
result = calculate(input_data)
65+
66+
# Assert
67+
assert result == 2
68+
69+
# Collect performance data (to be implemented)
70+
push_to_influx("calculation_time", 0.001, {
71+
"test_name": "test_calculation_accuracy",
72+
"feature": "accuracy"
73+
})
74+
```
75+
76+
### Tag Usage Specifications
77+
78+
#### 1. Level Tags (Required)
79+
```python
80+
@pytest.mark.stage(0) # Unit test
81+
@pytest.mark.stage(1) # Smoke test
82+
@pytest.mark.stage(2) # Regression test
83+
@pytest.mark.stage(3) # Release test
84+
```
85+
86+
#### 2. Feature Tags (Recommended)
87+
```python
88+
@pytest.mark.feature("performance") # Performance test
89+
@pytest.mark.feature("accuracy") # Accuracy test
90+
```
91+
92+
#### 3. Platform Tags (Optional)
93+
```python
94+
@pytest.mark.platform("gpu") # Only execute on GPU platform
95+
@pytest.mark.platform("npu") # Only execute on NPU platform
96+
# Default no tag, execute on all platforms
97+
```
98+
99+
#### 4. Combined Usage
100+
```python
101+
@pytest.mark.stage(2)
102+
@pytest.mark.feature("performance")
103+
@pytest.mark.gpu
104+
def test_gpu_performance(self):
105+
"""GPU Performance Test"""
106+
pass
107+
```
108+
109+
### Test Method Naming Convention
110+
111+
```python
112+
def test_[scenario]_[expected_result]:
113+
"""Test scenario description"""
114+
pass
115+
116+
# Example:
117+
def test_calculation_returns_correct_result():
118+
"""Test calculation returns correct result"""
119+
pass
120+
121+
```
122+
123+
### Assertion Specification
124+
125+
```python
126+
# Recommended: Clear assertion messages
127+
assert result == expected, f"Expected {expected}, actual {result}"
128+
129+
# Recommended: Use pytest built-in assertions
130+
assert isinstance(result, dict)
131+
assert len(items) > 0, "Result list should not be empty"
132+
133+
# Data validation
134+
assert 0 <= accuracy <= 1.0, "Accuracy should be in the range of 0-1"
135+
assert response.status_code == 200
136+
```
137+
138+
## Usage
139+
140+
### Install Dependencies
141+
```bash
142+
pip install -r requirements.txt
143+
```
144+
145+
### Run Tests
146+
147+
#### 1. Run by Levels
148+
```bash
149+
# Run all tests
150+
pytest
151+
152+
# Run specific levels
153+
pytest --stage=1 # Only run smoke tests
154+
pytest --stage=2,3 # Run regression and release tests
155+
pytest --stage=1+ # Run smoke and all higher level tests
156+
```
157+
158+
#### 2. Run by Features
159+
```bash
160+
# Run specific feature tests
161+
pytest --feature=accuracy
162+
pytest --feature=performance,accuracy
163+
```
164+
165+
#### 3. Run by Platforms
166+
```bash
167+
# Run all tests (default)
168+
pytest
169+
170+
# Only run GPU-related tests
171+
pytest --platform=gpu
172+
173+
# Exclude NPU tests
174+
pytest --platform=!npu
175+
```
176+
177+
#### 4. Combined Filtering
178+
```bash
179+
# Run performance regression tests on GPU platform
180+
pytest --stage=2 --platform=gpu --feature=performance
181+
```
182+
183+

test/README_zh.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# UCM Pytest 测试框架
2+
3+
基于pytest的测试框架,支持多级别测试、平台标记、性能数据收集和Allure报告生成。
4+
5+
## 框架特性
6+
7+
- [x] 🏗️ **多级别测试**: Unit(0) → Smoke(1) → Regression(2) → Release(3)
8+
- [x] 🏷️ **灵活标记**: 支持功能标签和平台标记
9+
- [ ] 📊 **数据收集**: 集成InfluxDB性能数据推送
10+
- [ ] 📋 **精美报告**: Allure测试报告集成
11+
- [ ] 🔧 **便捷工具**: 丰富的测试工具和公共方法
12+
13+
## 测试级别定义
14+
15+
| 级别 | 名称 | 说明 | 执行时机 |
16+
|-----|------|------|----------|
17+
| 0 | Unit | 单元测试 | 每次代码提交 |
18+
| 1 | Smoke | 冒烟测试 | 构建验证 |
19+
| 2 | Regression | 回归测试 | 版本发布前 |
20+
| 3 | Release | 发布测试 | 生产环境验证 |
21+
22+
## 目录结构
23+
24+
```
25+
project/
26+
├── tests/
27+
│ ├── config.yaml # 测试框架配置文件
28+
│ ├── conftest.py # pytest配置和fixtures,程序主入口
29+
│ ├── common/ # 通用工具库
30+
│ │ ├── __init__.py
31+
│ │ ├── config_utils.py # 配置文件读取工具
32+
│ │ ├── influxdb_utils.py # InfluxDB写入工具
33+
│ │ ├── allure_utils.py # Allure报告工具
34+
│ ├── suites/ # 测试用例目录
35+
│ │ ├── unit/ # 单元测试 (stage 0)
36+
│ │ ├── smoke/ # 冒烟测试 (stage 1)
37+
│ │ ├── regression/ # 回归测试 (stage 2)
38+
│ │ └── release/ # 版本测试 (stage 3)
39+
├── requirements.txt # 依赖包
40+
├── pytest.ini # pytest配置
41+
└── README.md # 用户指南
42+
```
43+
44+
## 测试用例标准
45+
46+
### 基本结构
47+
48+
```python
49+
import pytest
50+
from tests.common.influxdb_utils import push_to_influx
51+
from tests.common.test_utils import setup_test_env
52+
53+
class TestExample:
54+
"""测试示例类"""
55+
56+
@pytest.mark.stage(2)
57+
@pytest.mark.feature("accuracy")
58+
def test_calculation_accuracy(self):
59+
"""测试计算准确性"""
60+
# Arrange
61+
input_data = 1 + 1
62+
63+
# Act
64+
result = calculate(input_data)
65+
66+
# Assert
67+
assert result == 2
68+
69+
# 收集性能数据(待实现)
70+
push_to_influx("calculation_time", 0.001, {
71+
"test_name": "test_calculation_accuracy",
72+
"feature": "accuracy"
73+
})
74+
```
75+
76+
### 标记使用规范
77+
78+
#### 1. 级别标记 (必需)
79+
```python
80+
@pytest.mark.stage(0) # 单元测试
81+
@pytest.mark.stage(1) # 冒烟测试
82+
@pytest.mark.stage(2) # 回归测试
83+
@pytest.mark.stage(3) # 发布测试
84+
```
85+
86+
#### 2. 功能标记 (推荐)
87+
```python
88+
@pytest.mark.feature("performance") # 性能测试
89+
@pytest.mark.feature("accuracy") # 准确性测试
90+
```
91+
92+
#### 3. 平台标记 (可选)
93+
```python
94+
@pytest.mark.platform("gpu") # 仅GPU平台执行
95+
@pytest.mark.platform("npu") # 仅NPU平台执行
96+
# 默认无标记,所有平台都执行
97+
```

test/common/__init__.py

Whitespace-only changes.

test/common/allure_utils.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
"""
2+
Allure Report Integration Utility
3+
Provides convenient Allure report generation and customization functions
4+
"""

test/common/config_utils.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"""
2+
Configuration File Utility
3+
Provides functionality to read and parse configuration files
4+
"""
5+
import yaml
6+
import os
7+
from typing import Dict, Any, Optional
8+
9+
10+
class ConfigUtils:
11+
"""
12+
Configuration File Utility Class
13+
Provides functionality to read and parse configuration files
14+
"""
15+
_instance = None
16+
_config = None
17+
18+
def __new__(cls):
19+
if cls._instance is None:
20+
cls._instance = super(ConfigUtils, cls).__new__(cls)
21+
return cls._instance
22+
23+
def __init__(self, config_file=None):
24+
if not hasattr(self, 'initialized'):
25+
if config_file is None:
26+
# Default configuration file path
27+
current_dir = os.path.dirname(os.path.abspath(__file__))
28+
self.config_file = os.path.join(current_dir, "..", "config.yaml")
29+
else:
30+
self.config_file = config_file
31+
self.initialized = True
32+
33+
def read_config(self) -> Dict[str, Any]:
34+
"""Read configuration file"""
35+
if self._config is None:
36+
try:
37+
with open(self.config_file, 'r', encoding='utf-8') as file:
38+
self._config = yaml.safe_load(file) or {}
39+
except FileNotFoundError:
40+
print(f"Configuration file {self.config_file} not found")
41+
self._config = {}
42+
except yaml.YAMLError as e:
43+
print(f"Failed to parse configuration file: {e}")
44+
self._config = {}
45+
return self._config
46+
47+
def get_config(self, key: str, default: Any = None) -> Any:
48+
"""Get configuration item"""
49+
config = self.read_config()
50+
return config.get(key, default)
51+
52+
def get_nested_config(self, key_path: str, default: Any = None) -> Any:
53+
"""Get nested configuration item, supports dot-separated paths like 'influxdb.host'"""
54+
config = self.read_config()
55+
keys = key_path.split('.')
56+
value = config
57+
58+
try:
59+
for key in keys:
60+
value = value[key]
61+
return value
62+
except (KeyError, TypeError):
63+
return default
64+
65+
66+
# Global configuration instance
67+
config_utils = ConfigUtils()
68+
69+
70+
if __name__ == "__main__":
71+
# Read configuration file
72+
influxdb_config = config_utils.get_config("influxdb")
73+
print("InfluxDB configuration:", influxdb_config)
74+
75+
# Get configuration using nested path
76+
host = config_utils.get_nested_config("influxdb.host", "localhost")
77+
print(f"InfluxDB host: {host}")

0 commit comments

Comments
 (0)