Skip to content

Commit 84cd6a9

Browse files
committed
add
1 parent b4f8a5b commit 84cd6a9

File tree

10 files changed

+1616
-1
lines changed

10 files changed

+1616
-1
lines changed

development/FINAL_SUMMARY.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# ✅ 完成:自动测试发现功能
2+
3+
## 目标
4+
5+
确保所有使用 `@evaluation_test` 装饰的函数都能被 pytest 自动发现,无论函数名是否符合 pytest 命名规范。
6+
7+
## 实现方案
8+
9+
### 核心机制:自动注册
10+
11+
当函数名不以 `test_` 开头时,decorator 会:
12+
1. 自动在调用者的全局命名空间中注册一个以 `test_` 开头的别名
13+
2. Pytest 扫描模块时会发现这个别名
14+
3. 用户无需修改任何代码或命名
15+
16+
### 代码修改
17+
18+
#### 1. `eval_protocol/pytest/evaluation_test.py`
19+
- ✅ 移除了警告功能
20+
- ✅ 添加了自动注册逻辑(使用 `sys._getframe` 访问调用者的全局命名空间)
21+
22+
#### 2. `eval_protocol/pytest/parameterize.py`
23+
- ✅ 确保 wrapper 的 `__name__` 属性以 `test_` 开头
24+
25+
#### 3. `eval_protocol/pytest/dual_mode_wrapper.py`
26+
- ✅ 确保 dual_mode_wrapper 的 `__name__` 属性以 `test_` 开头
27+
28+
## 使用示例
29+
30+
```python
31+
from eval_protocol.pytest import evaluation_test
32+
from eval_protocol.models import EvaluationRow, EvaluateResult
33+
34+
# ✅ 不需要以 test_ 开头 - 会自动注册为 test_my_evaluation
35+
@evaluation_test(
36+
input_rows=[[EvaluationRow(messages=[{"role": "user", "content": "Hello"}])]]
37+
)
38+
async def my_evaluation(row: EvaluationRow) -> EvaluationRow:
39+
row.evaluation_result = EvaluateResult(score=1.0)
40+
return row
41+
42+
# ✅ 已经符合命名规范 - 正常工作
43+
@evaluation_test(
44+
input_rows=[[EvaluationRow(messages=[{"role": "user", "content": "Hello"}])]]
45+
)
46+
async def test_my_evaluation(row: EvaluationRow) -> EvaluationRow:
47+
row.evaluation_result = EvaluateResult(score=1.0)
48+
return row
49+
```
50+
51+
## 验证结果
52+
53+
```bash
54+
$ pytest --collect-only tests/test_auto_discovery_simple.py -v
55+
collected 2 items
56+
57+
<Module test_auto_discovery_simple.py>
58+
<Coroutine test_my_custom_eval[rows(len=1)]> # 自动注册!
59+
<Coroutine test_proper_eval[rows(len=1)]>
60+
61+
$ pytest tests/test_auto_discovery_simple.py -v
62+
============================== 2 passed in 0.15s ==============================
63+
```
64+
65+
## 特点
66+
67+
### ✅ 优点
68+
1. **零配置**:无需任何额外配置
69+
2. **无需警告**:静默自动处理,不打扰用户
70+
3. **完全兼容**:不影响已有代码
71+
4. **简单直接**:用户只需使用 `@evaluation_test`,其他都自动处理
72+
5. **可靠**:经过测试验证
73+
74+
### 🎯 工作原理
75+
- Pytest 通过扫描模块的全局命名空间来发现测试
76+
- 我们在装饰时自动在命名空间中注册正确命名的别名
77+
- 用户原始函数名保持不变,可以继续使用
78+
79+
## 测试覆盖
80+
81+
-`tests/test_auto_discovery_simple.py` - 验证自动发现功能
82+
- 测试不以 `test_` 开头的函数能被发现
83+
- 测试以 `test_` 开头的函数正常工作
84+
- 所有测试通过
85+
86+
## 文档
87+
88+
- `development/auto_test_discovery.md` - 详细技术文档
89+
- `development/FINAL_SUMMARY.md` - 本文档
90+
91+
## 总结
92+
93+
现在,用户只需要:
94+
95+
```python
96+
@evaluation_test(...)
97+
async def any_function_name(row: EvaluationRow) -> EvaluationRow:
98+
# 无论函数名是什么,都能被 pytest 发现!
99+
...
100+
```
101+
102+
**就这么简单!** 🎉
103+
104+
不需要:
105+
- ❌ 记住命名规范
106+
- ❌ 收到警告信息
107+
- ❌ 手动配置 pytest
108+
- ❌ 修改现有代码
109+
110+
只要使用 `@evaluation_test`,就能保证测试被发现!✨
111+

development/auto_test_discovery.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# 自动测试发现功能 (Auto Test Discovery)
2+
3+
## 概述
4+
5+
`@evaluation_test` decorator 现在会自动确保所有装饰的函数都能被 pytest 发现,无论函数名是否遵循 pytest 命名规范。
6+
7+
## 功能说明
8+
9+
### 核心机制
10+
11+
当你使用 `@evaluation_test` 装饰一个函数时:
12+
13+
1. **如果函数名以 `test_` 开头**:正常工作,无需额外处理
14+
2. **如果函数名不以 `test_` 开头**:decorator 会自动在模块的全局命名空间中注册一个以 `test_` 开头的别名
15+
16+
### 实现细节
17+
18+
-`evaluation_test.py` 中,decorator 检查函数名
19+
- 如果不以 `test_` 开头,使用 `sys._getframe(1).f_globals` 获取调用者的全局命名空间
20+
- 在该命名空间中注册 `test_{original_name}` 别名
21+
- Pytest 扫描模块时会发现这个别名
22+
23+
## 使用示例
24+
25+
```python
26+
from eval_protocol.pytest import evaluation_test
27+
from eval_protocol.models import EvaluationRow, EvaluateResult
28+
29+
# ✅ 这个函数名不以 test_ 开头,但仍然会被发现
30+
@evaluation_test(
31+
input_rows=[[
32+
EvaluationRow(messages=[{"role": "user", "content": "Test"}])
33+
]]
34+
)
35+
async def my_custom_evaluation(row: EvaluationRow) -> EvaluationRow:
36+
"""
37+
Pytest 会自动发现这个函数作为 'test_my_custom_evaluation'
38+
"""
39+
row.evaluation_result = EvaluateResult(score=1.0)
40+
return row
41+
42+
# ✅ 这个函数名已经符合规范
43+
@evaluation_test(
44+
input_rows=[[
45+
EvaluationRow(messages=[{"role": "user", "content": "Test"}])
46+
]]
47+
)
48+
async def test_my_evaluation(row: EvaluationRow) -> EvaluationRow:
49+
"""
50+
这个函数已经以 test_ 开头,正常工作
51+
"""
52+
row.evaluation_result = EvaluateResult(score=1.0)
53+
return row
54+
```
55+
56+
## 验证
57+
58+
运行 pytest collection 可以看到两个测试都被发现:
59+
60+
```bash
61+
$ pytest --collect-only
62+
<Module my_tests.py>
63+
<Coroutine test_my_custom_evaluation[rows(len=1)]>
64+
<Coroutine test_my_evaluation[rows(len=1)]>
65+
```
66+
67+
## 代码修改
68+
69+
### 1. `eval_protocol/pytest/evaluation_test.py`
70+
71+
在 decorator 返回之前添加自动注册逻辑:
72+
73+
```python
74+
# Auto-register the test function in the caller's namespace with 'test_' prefix
75+
original_name = test_func.__name__
76+
if not original_name.startswith('test_'):
77+
import sys
78+
frame = sys._getframe(1)
79+
caller_globals = frame.f_globals
80+
test_name = f'test_{original_name}'
81+
if test_name not in caller_globals:
82+
caller_globals[test_name] = dual_mode_wrapper
83+
```
84+
85+
### 2. `eval_protocol/pytest/parameterize.py`
86+
87+
确保 wrapper 的 `__name__` 属性被修正:
88+
89+
```python
90+
# Ensure wrapper name starts with 'test_' for pytest discovery
91+
original_name = test_func.__name__
92+
if not original_name.startswith('test_'):
93+
wrapper.__name__ = f'test_{original_name}'
94+
```
95+
96+
### 3. `eval_protocol/pytest/dual_mode_wrapper.py`
97+
98+
同样确保 dual_mode_wrapper 的名称被修正:
99+
100+
```python
101+
# Ensure the wrapper name starts with 'test_' for pytest discovery
102+
original_name = test_func.__name__
103+
if not original_name.startswith('test_'):
104+
dual_mode_wrapper.__name__ = f'test_{original_name}'
105+
```
106+
107+
## 测试
108+
109+
参考 `tests/test_auto_discovery_simple.py` 查看完整的测试示例。
110+
111+
运行测试:
112+
```bash
113+
pytest tests/test_auto_discovery_simple.py -v
114+
```
115+
116+
## 优点
117+
118+
1. ✅ 用户不需要记住命名规范
119+
2. ✅ 所有使用 `@evaluation_test` 的函数都能被 pytest 发现
120+
3. ✅ 无需任何配置
121+
4. ✅ 向后兼容(已经使用 `test_` 前缀的函数继续正常工作)
122+
5. ✅ 无警告,自动静默处理
123+
124+
## 总结
125+
126+
现在,只要你使用 `@evaluation_test` 装饰函数,就可以保证它能被 pytest 发现,无论你如何命名这个函数!🎉
127+

0 commit comments

Comments
 (0)