@wwkit/harness 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/extract.md +2 -14
- package/agents/lint.md +368 -0
- package/agents/pyit.md +361 -0
- package/agents/pyut.md +347 -0
- package/agents/query.md +2 -14
- package/agents/revise.md +2 -14
- package/agents/work.md +631 -0
- package/commands/fix.md +77 -0
- package/commands/git-sync.md +218 -0
- package/commands/net-port.md +364 -0
- package/commands/pyit.md +6 -0
- package/commands/pyut.md +6 -0
- package/commands/resume.md +104 -0
- package/package.json +4 -2
- package/plugins/work-bootstrap.js +77 -0
- package/scripts/work-review-package +50 -0
- package/scripts/work-task-brief +27 -0
- package/scripts/work-workspace +31 -0
- package/skills/better-skill/SKILL.md +124 -0
- package/skills/blame-skill/SKILL.md +201 -0
- package/skills/lint-ai-fix/SKILL.md +141 -0
- package/skills/lint-config-setup/SKILL.md +106 -0
- package/skills/lint-config-setup/references/languages/js.md +110 -0
- package/skills/lint-config-setup/references/languages/py.md +89 -0
- package/skills/lint-env-ensure/SKILL.md +92 -0
- package/skills/lint-env-ensure/references/config.md +65 -0
- package/skills/lint-language-detect/SKILL.md +79 -0
- package/skills/lint-language-detect/references/detect-language.js +65 -0
- package/skills/lint-rules-analyze/SKILL.md +129 -0
- package/skills/lint-suitability-check/SKILL.md +84 -0
- package/skills/lint-tool-fix/SKILL.md +94 -0
- package/skills/new-skill/SKILL.md +227 -0
- package/skills/new-skill/references/template.md +53 -0
- package/skills/new-skill/references/workflow-patterns.md +104 -0
- package/skills/pytest-case-create/SKILL.md +327 -0
- package/skills/pytest-case-create/references/test-standards.md +244 -0
- package/skills/pytest-case-fix/SKILL.md +274 -0
- package/skills/pytest-coverage-analyze/SKILL.md +226 -0
- package/skills/pytest-coverage-analyze/references/scoring-rules.md +57 -0
- package/skills/pytest-env-ensure/SKILL.md +198 -0
- package/skills/pytest-env-ensure/references/config.md +145 -0
- package/skills/pytest-execute/SKILL.md +155 -0
- package/skills/pytest-sample/SKILL.md +164 -0
- package/skills/pytest-sample/references/src/pytest-sample/Calculator.py +67 -0
- package/skills/pytest-sample/references/src/pytest-sample/ConfigManager.py +68 -0
- package/skills/pytest-sample/references/src/pytest-sample/FileProcessor.py +53 -0
- package/skills/pytest-sample/references/src/pytest-sample/OrderService.py +82 -0
- package/skills/pytest-sample/references/src/pytest-sample/TokenGenerator.py +50 -0
- package/skills/pytest-sample/references/src/pytest-sample/UserService.py +45 -0
- package/skills/pytest-sample/references/src/pytest-sample/__init__.py +0 -0
- package/skills/pytest-suitability-check/SKILL.md +224 -0
- package/skills/read-docs/SKILL.md +134 -0
- package/skills/read-docs/references/opencode/agents/cases.md +206 -0
- package/skills/read-docs/references/opencode/agents/design-pattern.md +47 -0
- package/skills/read-docs/references/opencode/agents/detail.md +191 -0
- package/skills/read-docs/references/opencode/agents/examples.md +100 -0
- package/skills/read-docs/references/opencode/agents/index.md +309 -0
- package/skills/read-docs/references/opencode/agents/parallel-dispatch.md +149 -0
- package/skills/read-docs/references/opencode/agents/subagent-internals.md +217 -0
- package/skills/read-docs/references/opencode/agents/workflow.md +161 -0
- package/skills/read-docs/references/opencode/cli/commands/acp.md +32 -0
- package/skills/read-docs/references/opencode/cli/commands/agent.md +16 -0
- package/skills/read-docs/references/opencode/cli/commands/attach.md +20 -0
- package/skills/read-docs/references/opencode/cli/commands/mcp.md +37 -0
- package/skills/read-docs/references/opencode/cli/commands/others.md +49 -0
- package/skills/read-docs/references/opencode/cli/commands/plugin.md +13 -0
- package/skills/read-docs/references/opencode/cli/commands/provider.md +44 -0
- package/skills/read-docs/references/opencode/cli/commands/run.md +81 -0
- package/skills/read-docs/references/opencode/cli/commands/serve.md +84 -0
- package/skills/read-docs/references/opencode/cli/commands/session.md +38 -0
- package/skills/read-docs/references/opencode/cli/commands/web.md +15 -0
- package/skills/read-docs/references/opencode/cli/env.md +39 -0
- package/skills/read-docs/references/opencode/cli/index.md +19 -0
- package/skills/read-docs/references/opencode/cli/tui.md +35 -0
- package/skills/read-docs/references/opencode/commands/examples.md +42 -0
- package/skills/read-docs/references/opencode/commands/index.md +185 -0
- package/skills/read-docs/references/opencode/config/provider.md +152 -0
- package/skills/read-docs/references/opencode/formatter/index.md +71 -0
- package/skills/read-docs/references/opencode/guide/config.md +419 -0
- package/skills/read-docs/references/opencode/guide/formatters.md +70 -0
- package/skills/read-docs/references/opencode/guide/index.md +37 -0
- package/skills/read-docs/references/opencode/guide/providers.md +31 -0
- package/skills/read-docs/references/opencode/guide/rules.md +63 -0
- package/skills/read-docs/references/opencode/plugins/examples.md +75 -0
- package/skills/read-docs/references/opencode/plugins/index.md +188 -0
- package/skills/read-docs/references/opencode/reference/index.md +119 -0
- package/skills/read-docs/references/opencode/rule/index.md +78 -0
- package/skills/read-docs/references/opencode/skills/detail.md +113 -0
- package/skills/read-docs/references/opencode/skills/examples.md +141 -0
- package/skills/read-docs/references/opencode/skills/index.md +126 -0
- package/skills/read-docs/references/opencode/skills/workflow.md +146 -0
- package/skills/read-docs/references/opencode/tests/agent.md +10 -0
- package/skills/read-docs/references/opencode/tests/config.md +60 -0
- package/skills/read-docs/references/opencode/tests/file.md +12 -0
- package/skills/read-docs/references/opencode/tests/serve.md +18 -0
- package/skills/read-docs/references/opencode/tests/session.md +31 -0
- package/skills/read-docs/references/opencode/tests/web.md +17 -0
- package/skills/read-docs/references/opencode/tools/arguments.md +305 -0
- package/skills/read-docs/references/opencode/tools/context.md +18 -0
- package/skills/read-docs/references/opencode/tools/custom.md +111 -0
- package/skills/read-docs/references/opencode/tools/detail.md +104 -0
- package/skills/read-docs/references/opencode/tools/examples.md +71 -0
- package/skills/read-docs/references/opencode/tools/index.md +56 -0
- package/skills/read-docs/references/opencode/tools/lsp.md +26 -0
- package/skills/read-docs/references/opencode/tools/mcp.md +132 -0
- package/skills/read-docs/references/opencode/train/README.md +135 -0
- package/skills/read-docs/references/opencode/train/agent-basic.md +772 -0
- package/skills/read-docs/references/opencode/train/command-basic.md +668 -0
- package/skills/read-docs/references/opencode/train/config-basic.md +509 -0
- package/skills/read-docs/references/opencode/train/index.md +164 -0
- package/skills/read-docs/references/opencode/train/practice.md +873 -0
- package/skills/read-docs/references/opencode/train/skill-basic.md +608 -0
- package/skills/read-docs/references/opencode/tui/commands/config.md +32 -0
- package/skills/read-docs/references/opencode/tui/commands/editor.md +47 -0
- package/skills/read-docs/references/opencode/tui/commands/index.md +125 -0
- package/skills/read-docs/references/opencode/tui/commands/init.md +5 -0
- package/skills/read-docs/references/opencode/tui/index.md +26 -0
- package/skills/read-docs/references/superpowers/bootstrap.md +107 -0
- package/skills/read-docs/references/superpowers/comparison.md +77 -0
- package/skills/read-docs/references/superpowers/context.md +71 -0
- package/skills/read-docs/references/superpowers/index.md +58 -0
- package/skills/read-docs/references/superpowers/parallel.md +49 -0
- package/skills/read-docs/references/superpowers/sdd.md +183 -0
- package/skills/read-docs/references/superpowers/skills.md +68 -0
- package/skills/read-docs/references/superpowers/workflow.md +83 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pytest-env-ensure
|
|
3
|
+
description: |
|
|
4
|
+
检查 Python uv 项目环境并加载测试代理配置。验证 uv 项目结构、检查并安装依赖插件、读取配置清单。
|
|
5
|
+
适用:测试代理启动前的环境准备,任何需要验证 pytest 运行环境的场景。
|
|
6
|
+
不适用:非 uv 管理的 Python 项目、非测试相关的环境检查。
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# 环境检查与配置加载
|
|
10
|
+
|
|
11
|
+
## 工作流模式
|
|
12
|
+
|
|
13
|
+
本 Skill 采用 **顺序执行** 工作流:
|
|
14
|
+
|
|
15
|
+
1. **uv 项目检查**:验证是否为 uv 管理的 Python 项目
|
|
16
|
+
2. **依赖检查与安装**:检查依赖插件,未安装则自动安装
|
|
17
|
+
3. **安装验证**:重新验证所有依赖是否可用
|
|
18
|
+
4. **配置加载**:读取配置清单,输出给调用方
|
|
19
|
+
|
|
20
|
+
## 输入
|
|
21
|
+
|
|
22
|
+
| 参数 | 必填 | 类型 | 说明 |
|
|
23
|
+
|------|------|------|------|
|
|
24
|
+
| 无 | - | - | 自动检测当前工程 |
|
|
25
|
+
|
|
26
|
+
## 输出
|
|
27
|
+
|
|
28
|
+
- 配置对象(包含 dependencies、loops、metrics、naming、types 等字段)
|
|
29
|
+
- 环境检查报告
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 阶段一:uv 项目检查
|
|
34
|
+
|
|
35
|
+
**操作**:
|
|
36
|
+
|
|
37
|
+
1. 检查 `pyproject.toml` 是否存在且包含 `[project]` 段
|
|
38
|
+
2. 检查 `.venv/` 目录是否存在
|
|
39
|
+
3. 运行 `uv run python --version` 验证 uv 可用
|
|
40
|
+
|
|
41
|
+
**决策**:
|
|
42
|
+
|
|
43
|
+
| 条件 | 动作 |
|
|
44
|
+
|------|------|
|
|
45
|
+
| pyproject.toml 存在且 .venv 存在 | 进入阶段二 |
|
|
46
|
+
| pyproject.toml 不存在 | **直接退出**,提示"当前 agent 仅支持 uv 项目,未找到 pyproject.toml" |
|
|
47
|
+
| .venv 不存在 | **直接退出**,提示"当前 agent 仅支持 uv 项目,未找到 .venv 目录,请先运行 uv sync" |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 阶段二:依赖检查与安装
|
|
52
|
+
|
|
53
|
+
**输入**:读取 `references/config.md` 的 dependencies 清单
|
|
54
|
+
|
|
55
|
+
**操作**:
|
|
56
|
+
|
|
57
|
+
1. 逐个执行 `check` 命令验证是否已安装
|
|
58
|
+
2. 对未安装的依赖,执行 `install` 命令
|
|
59
|
+
3. 安装失败 → 重试(最多 3 次,由 config 的 `env.install_retry` 控制)
|
|
60
|
+
4. `install` 为 null 的依赖(如 uv)→ 跳过安装,仅检查
|
|
61
|
+
|
|
62
|
+
**重试逻辑**:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
for each dependency:
|
|
66
|
+
if check passes:
|
|
67
|
+
mark as installed
|
|
68
|
+
else if install is null:
|
|
69
|
+
mark as missing (system-level, cannot auto-install)
|
|
70
|
+
else:
|
|
71
|
+
retry_count = 0
|
|
72
|
+
while retry_count < install_retry:
|
|
73
|
+
run install command
|
|
74
|
+
if check passes:
|
|
75
|
+
mark as installed
|
|
76
|
+
break
|
|
77
|
+
retry_count += 1
|
|
78
|
+
if still not installed:
|
|
79
|
+
mark as failed
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**决策**:
|
|
83
|
+
|
|
84
|
+
| 条件 | 动作 |
|
|
85
|
+
|------|------|
|
|
86
|
+
| 全部已安装 | 进入阶段三 |
|
|
87
|
+
| 有 required 依赖安装失败 | **直接退出**,列出失败的依赖 |
|
|
88
|
+
| 有非 required 依赖安装失败 | 记录警告,继续 |
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 阶段三:安装验证
|
|
93
|
+
|
|
94
|
+
**操作**:对所有依赖重新执行 `check` 命令
|
|
95
|
+
|
|
96
|
+
**决策**:
|
|
97
|
+
|
|
98
|
+
| 条件 | 动作 |
|
|
99
|
+
|------|------|
|
|
100
|
+
| 全部通过 | 进入阶段四 |
|
|
101
|
+
| 有 required 依赖未通过 | **直接退出**,列出未通过的依赖 |
|
|
102
|
+
| 有非 required 依赖未通过 | 记录警告,继续 |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 阶段四:pytest marker 注册检查
|
|
107
|
+
|
|
108
|
+
**操作**:
|
|
109
|
+
|
|
110
|
+
1. 读取 `pyproject.toml`
|
|
111
|
+
2. 检查 `[tool.pytest.ini_options]` 段是否存在
|
|
112
|
+
3. 检查 `markers` 列表是否包含 `unit` 和 `integration`
|
|
113
|
+
|
|
114
|
+
**需要注册的 marker**:
|
|
115
|
+
|
|
116
|
+
```toml
|
|
117
|
+
[tool.pytest.ini_options]
|
|
118
|
+
markers = [
|
|
119
|
+
"unit: 单元测试",
|
|
120
|
+
"integration: 集成测试",
|
|
121
|
+
]
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**决策**:
|
|
125
|
+
|
|
126
|
+
| 条件 | 动作 |
|
|
127
|
+
|------|------|
|
|
128
|
+
| marker 已注册 | 进入阶段五 |
|
|
129
|
+
| marker 未注册 | 在 pyproject.toml 中添加上述 marker 配置 |
|
|
130
|
+
| pyproject.toml 无 `[tool.pytest.ini_options]` 段 | 添加该段及 marker 配置 |
|
|
131
|
+
| 无法写入 pyproject.toml | 记录警告,提示用户手动添加 |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 阶段五:配置加载
|
|
136
|
+
|
|
137
|
+
**操作**:
|
|
138
|
+
|
|
139
|
+
1. 读取 `references/config.md`
|
|
140
|
+
2. 解析配置项:dependencies、env、loops、metrics(unit + integration)、naming、types
|
|
141
|
+
3. 输出配置对象给调用方(agent)
|
|
142
|
+
|
|
143
|
+
**输出格式**:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
## 环境检查报告
|
|
147
|
+
|
|
148
|
+
### 项目检查
|
|
149
|
+
- pyproject.toml: ✓
|
|
150
|
+
- .venv: ✓
|
|
151
|
+
- uv: ✓
|
|
152
|
+
|
|
153
|
+
### 依赖检查
|
|
154
|
+
| 依赖 | 状态 | 备注 |
|
|
155
|
+
|------|------|------|
|
|
156
|
+
| uv | ✓ 已安装 | 系统级 |
|
|
157
|
+
| pytest | ✓ 已安装 | - |
|
|
158
|
+
| pytest-cov | ✓ 已安装 | - |
|
|
159
|
+
|
|
160
|
+
### Marker 检查
|
|
161
|
+
- unit: ✓ 已注册
|
|
162
|
+
- integration: ✓ 已注册
|
|
163
|
+
|
|
164
|
+
### 配置已加载
|
|
165
|
+
- coverage_threshold: 90 (unit) / 70 (integration)
|
|
166
|
+
- outer_max: 3
|
|
167
|
+
- inner_max: 3
|
|
168
|
+
- test_root: tests
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 失败处理
|
|
174
|
+
|
|
175
|
+
| 场景 | 处理方式 |
|
|
176
|
+
|------|---------|
|
|
177
|
+
| 非 uv 项目 | 直接退出,提示仅支持 uv 项目 |
|
|
178
|
+
| required 依赖安装失败(重试 3 次) | 退出,列出失败依赖 |
|
|
179
|
+
| required 依赖验证不通过 | 退出,列出未通过依赖 |
|
|
180
|
+
| config.md 不存在或格式错误 | 退出,提示配置文件缺失 |
|
|
181
|
+
| 非项目特定错误 | 记录警告,不阻断流程 |
|
|
182
|
+
|
|
183
|
+
## 一定要做
|
|
184
|
+
|
|
185
|
+
1. 必须先检查 uv 项目结构,不满足直接退出
|
|
186
|
+
2. 依赖检查必须读取 config.md 的 dependencies 清单
|
|
187
|
+
3. 安装失败必须重试,重试次数由 config 控制
|
|
188
|
+
4. 安装后必须重新验证
|
|
189
|
+
5. 必须检查 pytest marker 注册,未注册时自动添加
|
|
190
|
+
6. 最终输出完整的配置对象给调用方
|
|
191
|
+
|
|
192
|
+
## 一定不要做
|
|
193
|
+
|
|
194
|
+
1. 不要跳过 uv 项目检查
|
|
195
|
+
2. 不要安装 install 为 null 的依赖(系统级工具)
|
|
196
|
+
3. 不要忽略 required 依赖的失败
|
|
197
|
+
4. 不要修改 config.md 文件内容
|
|
198
|
+
5. 不要预设任何项目特定的依赖或配置
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# pytest 测试代理配置清单
|
|
2
|
+
|
|
3
|
+
> 本文件是测试代理的全局配置,agent 启动时首先读取,后续所有 skill 共享。
|
|
4
|
+
|
|
5
|
+
## 依赖工具
|
|
6
|
+
|
|
7
|
+
| name | check | required | install |
|
|
8
|
+
|------|-------|----------|---------|
|
|
9
|
+
| uv | `uv --version` | true | null(系统级工具,需手动安装) |
|
|
10
|
+
| pytest | `uv run pytest --version` | true | `uv add --dev pytest` |
|
|
11
|
+
| pytest-cov | `uv run pytest --cov --help` | true | `uv add --dev pytest-cov` |
|
|
12
|
+
| pytest-timeout | `uv run pytest --timeout=1 --help` | true | `uv add --dev pytest-timeout` |
|
|
13
|
+
| pytest-html | `uv run pytest --html --help` | false | `uv add --dev pytest-html` |
|
|
14
|
+
|
|
15
|
+
## 环境检查
|
|
16
|
+
|
|
17
|
+
| 参数 | 值 | 说明 |
|
|
18
|
+
|------|-----|------|
|
|
19
|
+
| uv_project_check | true | 必须是 uv 项目(pyproject.toml + .venv/) |
|
|
20
|
+
| install_retry | 3 | 插件安装失败重试次数 |
|
|
21
|
+
|
|
22
|
+
## 超时配置
|
|
23
|
+
|
|
24
|
+
| 参数 | 值 | 说明 |
|
|
25
|
+
|------|-----|------|
|
|
26
|
+
| test_timeout_unit | 60 | 单元测试单用例超时(秒) |
|
|
27
|
+
| test_timeout_integration | 300 | 集成测试单用例超时(秒) |
|
|
28
|
+
|
|
29
|
+
## Loop 控制
|
|
30
|
+
|
|
31
|
+
| 参数 | 值 | 说明 |
|
|
32
|
+
|------|-----|------|
|
|
33
|
+
| outer_max | 3 | 外层 loop(coverage→create→execute)最大轮次 |
|
|
34
|
+
| inner_max | 3 | 内层 loop(fix→execute)最大轮次 |
|
|
35
|
+
|
|
36
|
+
## 测试指标 — 单元测试(unit)
|
|
37
|
+
|
|
38
|
+
| 参数 | 值 | 说明 |
|
|
39
|
+
|------|-----|------|
|
|
40
|
+
| coverage_threshold | 90 | 覆盖率达标线 |
|
|
41
|
+
| line_coverage_weight | 30 | 行覆盖率权重 |
|
|
42
|
+
| branch_coverage_weight | 30 | 分支覆盖率权重 |
|
|
43
|
+
| function_coverage_weight | 20 | 函数覆盖率权重 |
|
|
44
|
+
| test_quality_weight | 20 | 用例质量权重 |
|
|
45
|
+
|
|
46
|
+
## 测试指标 — 集成测试(integration)
|
|
47
|
+
|
|
48
|
+
| 参数 | 值 | 说明 |
|
|
49
|
+
|------|-----|------|
|
|
50
|
+
| coverage_threshold | 70 | 覆盖率达标线 |
|
|
51
|
+
| line_coverage_weight | 20 | 行覆盖率权重 |
|
|
52
|
+
| branch_coverage_weight | 20 | 分支覆盖率权重 |
|
|
53
|
+
| function_coverage_weight | 10 | 函数覆盖率权重 |
|
|
54
|
+
| test_quality_weight | 50 | 用例质量权重(更重场景质量) |
|
|
55
|
+
|
|
56
|
+
## 命名规则
|
|
57
|
+
|
|
58
|
+
| 参数 | 值 | 说明 |
|
|
59
|
+
|------|-----|------|
|
|
60
|
+
| test_root | tests | 测试根目录 |
|
|
61
|
+
| dir_mapping_pattern | `tests/{type}/{package_module}` | 归一化仅去除 src/ 前缀,保留包名 |
|
|
62
|
+
| report_dir_pattern | `{test_dir}/reports/{YYYYMMDD_HHMMSS}/` | 报告输出目录 |
|
|
63
|
+
| report.test_report | `test_report.md` | 最终测试报告文件名 |
|
|
64
|
+
| report.bug_list | `bug_list.md` | 源码 Bug 清单文件名 |
|
|
65
|
+
| file.pattern | `test_{ModuleName}.py` | 测试文件命名 |
|
|
66
|
+
| class.pattern | `test_{ModuleName}` | 测试类命名(与文件名一致) |
|
|
67
|
+
| method.pattern | `test_{action}_{expected}` | 测试方法命名 |
|
|
68
|
+
| fixture_file.name | conftest.py | 共享 fixture 文件名 |
|
|
69
|
+
| fixture_file.data_dir | fixtures | 测试数据目录名 |
|
|
70
|
+
|
|
71
|
+
### 目录映射算法(pyut/pyit agent Step 1 唯一权威定义)
|
|
72
|
+
|
|
73
|
+
> pyut/pyit agent 的 Step 1 直接引用本算法,不另行重复定义。
|
|
74
|
+
|
|
75
|
+
当用户未显式指定测试目录时,agent 按以下步骤自动推导 `test_dir`:
|
|
76
|
+
|
|
77
|
+
**输入**: `source_path`(源码路径),`test_type`(unit 或 integration)
|
|
78
|
+
|
|
79
|
+
**Step 1: 归一化源码路径**
|
|
80
|
+
|
|
81
|
+
按顺序执行:
|
|
82
|
+
|
|
83
|
+
1. 文件 → 取父目录
|
|
84
|
+
2. 绝对路径 → 转为相对路径(相对于项目根目录)
|
|
85
|
+
3. 含 `..` → 先 resolve 为标准路径再继续
|
|
86
|
+
4. 为 `.` 或空 → 报错"请提供子目录路径,如 src/mypackage"
|
|
87
|
+
5. 去除开头的 `./`
|
|
88
|
+
6. 去除开头的 `src/`(仅去除一次)
|
|
89
|
+
7. 归一化后为空 → 报错"归一化后路径为空,请提供 src/ 下的子目录"
|
|
90
|
+
|
|
91
|
+
**归一化规则**:仅去除 `src/` 前缀,**保留包名及子模块路径**。无 `src/` 前缀的路径(flat layout)保持原样。
|
|
92
|
+
|
|
93
|
+
**Step 2: 映射**
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
test_dir = tests/{test_type}/{归一化路径}/
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Step 3: 验证与创建**
|
|
100
|
+
|
|
101
|
+
- `tests/` 不存在 → 自动创建 `tests/{test_type}/` 目录结构
|
|
102
|
+
- 映射目录不存在 → 自动创建,标记为全新模式(无已有测试)
|
|
103
|
+
|
|
104
|
+
### 映射示例
|
|
105
|
+
|
|
106
|
+
| 源码路径 | test_type | 归一化 | 自动推导 test_dir |
|
|
107
|
+
|---------|-----------|--------|------------------|
|
|
108
|
+
| `src/pytest-sample` | unit | `pytest-sample` | `tests/unit/pytest-sample/` |
|
|
109
|
+
| `src/mypackage/sub` | unit | `mypackage/sub` | `tests/unit/mypackage/sub/` |
|
|
110
|
+
| `src/mypackage/MyService.py` | unit | `mypackage` | `tests/unit/mypackage/` |
|
|
111
|
+
| `src/pytest-sample` | integration | `pytest-sample` | `tests/integration/pytest-sample/` |
|
|
112
|
+
| `blues_lib/util` | integration | `blues_lib/util` | `tests/integration/blues_lib/util/` |
|
|
113
|
+
| `mypackage/sub`(flat layout) | unit | `mypackage/sub` | `tests/unit/mypackage/sub/` |
|
|
114
|
+
|
|
115
|
+
### 命名示例
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
源码路径: src/mypackage/myservice
|
|
119
|
+
模块名: MyService
|
|
120
|
+
测试目录: tests/unit/mypackage/
|
|
121
|
+
测试文件: tests/unit/mypackage/test_MyService.py
|
|
122
|
+
测试类: test_MyService
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 测试类型
|
|
126
|
+
|
|
127
|
+
### unit(单元测试)
|
|
128
|
+
|
|
129
|
+
| 参数 | 值 | 说明 |
|
|
130
|
+
|------|-----|------|
|
|
131
|
+
| dir | tests/unit | 测试目录 |
|
|
132
|
+
| marker | unit | pytest marker |
|
|
133
|
+
| mock_strategy | full | 全部 Mock 外部依赖 |
|
|
134
|
+
| coverage_focus | line, branch, function | 覆盖率关注点 |
|
|
135
|
+
| timeout | 60 | 单用例超时(秒) |
|
|
136
|
+
|
|
137
|
+
### integration(集成测试)
|
|
138
|
+
|
|
139
|
+
| 参数 | 值 | 说明 |
|
|
140
|
+
|------|-----|------|
|
|
141
|
+
| dir | tests/integration | 测试目录 |
|
|
142
|
+
| marker | integration | pytest marker |
|
|
143
|
+
| mock_strategy | minimal | 最少 Mock,真实调用 |
|
|
144
|
+
| coverage_focus | scenario, flow | 覆盖率关注点 |
|
|
145
|
+
| timeout | 300 | 单用例超时(秒) |
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pytest-execute
|
|
3
|
+
description: |
|
|
4
|
+
执行 pytest 测试用例并输出测试报告。根据 test_type 选择对应测试目录,运行用例并解析结果。
|
|
5
|
+
适用:测试代理的测试执行阶段,运行已创建的用例并收集结果。
|
|
6
|
+
不适用:创建测试用例(使用 pytest-case-create)、修复失败用例(使用 pytest-case-fix)。
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# 测试执行
|
|
10
|
+
|
|
11
|
+
## 工作流模式
|
|
12
|
+
|
|
13
|
+
本 Skill 采用 **顺序执行** 工作流:
|
|
14
|
+
|
|
15
|
+
1. **选择目录**:根据 test_type 选择测试目录
|
|
16
|
+
2. **执行测试**:运行 pytest
|
|
17
|
+
3. **解析结果**:提取通过/失败/跳过统计
|
|
18
|
+
4. **提取失败详情**:对每个失败用例提取详细信息
|
|
19
|
+
5. **输出报告**:测试报告 + 失败详情
|
|
20
|
+
|
|
21
|
+
## 输入
|
|
22
|
+
|
|
23
|
+
| 参数 | 必填 | 类型 | 说明 |
|
|
24
|
+
|------|------|------|------|
|
|
25
|
+
| target | 是 | string | 被测模块路径 |
|
|
26
|
+
| test_dir | 是 | string | 测试目录路径(由 agent Step 1 统一解析) |
|
|
27
|
+
| test_type | 是 | string | 测试类型:unit 或 integration |
|
|
28
|
+
| config | 是 | object | 来自 pytest-env-ensure 的配置对象 |
|
|
29
|
+
| test_files | 否 | list | 指定测试文件(不指定则运行 test_dir 下全部) |
|
|
30
|
+
|
|
31
|
+
## 输出
|
|
32
|
+
|
|
33
|
+
- 测试报告(通过数/失败数/跳过数)
|
|
34
|
+
- 失败详情列表(文件路径、用例名、错误类型、错误信息、堆栈)
|
|
35
|
+
- 决策结论(全部通过 → 回到 coverage-analyze;有失败 → 交给 case-fix)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 阶段一:选择目录
|
|
40
|
+
|
|
41
|
+
**操作**:使用传入的 `test_dir` 作为测试目录
|
|
42
|
+
|
|
43
|
+
如果指定了 test_files,则只运行指定的文件。
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 阶段二:执行测试
|
|
48
|
+
|
|
49
|
+
**操作**:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
# 运行 test_dir 下的测试(unit 超时 60s,integration 超时 300s)
|
|
53
|
+
uv run pytest "{test_dir}" -v --tb=short --log-level=INFO --timeout={timeout} -m {test_type}
|
|
54
|
+
|
|
55
|
+
# 如果指定了 test_files
|
|
56
|
+
uv run pytest {test_files} -v --tb=short --log-level=INFO --timeout={timeout} -m {test_type}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**参数说明**:
|
|
60
|
+
- `-v`:详细输出每个用例结果
|
|
61
|
+
- `--tb=short`:失败时输出简短堆栈
|
|
62
|
+
- `--log-level=INFO`:显示 INFO 级别日志
|
|
63
|
+
- `-m {type}`:只运行对应 marker 的测试
|
|
64
|
+
- `--timeout`:单用例超时秒数(unit=60, integration=300),来自 config
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 阶段三:解析结果
|
|
69
|
+
|
|
70
|
+
**操作**:从 pytest 输出中提取:
|
|
71
|
+
|
|
72
|
+
1. 统计数据:
|
|
73
|
+
- 通过数(passed)
|
|
74
|
+
- 失败数(failed)
|
|
75
|
+
- 跳过数(skipped)
|
|
76
|
+
- 错误数(error)
|
|
77
|
+
- 总数
|
|
78
|
+
|
|
79
|
+
2. 对每个失败/错误用例提取:
|
|
80
|
+
- 文件路径
|
|
81
|
+
- 类名
|
|
82
|
+
- 方法名
|
|
83
|
+
- 错误类型(AssertionError, TypeError, ImportError 等)
|
|
84
|
+
- 错误信息(第一行错误描述)
|
|
85
|
+
- 堆栈信息(--tb=short 格式)
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 阶段四:输出报告
|
|
90
|
+
|
|
91
|
+
**输出格式**:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
## 测试执行报告
|
|
95
|
+
|
|
96
|
+
### 统计
|
|
97
|
+
- 总数:XX
|
|
98
|
+
- 通过:XX
|
|
99
|
+
- 失败:XX
|
|
100
|
+
- 跳过:XX
|
|
101
|
+
- 错误:XX
|
|
102
|
+
- 通过率:XX%
|
|
103
|
+
|
|
104
|
+
### 失败详情(如有)
|
|
105
|
+
| # | 文件 | 类名 | 方法名 | 错误类型 | 错误信息 |
|
|
106
|
+
|---|------|------|--------|---------|---------|
|
|
107
|
+
| 1 | tests/unit/xxx/test_MyService.py | test_MyService | test_create_with_valid_data | AssertionError | assert result.id is not None |
|
|
108
|
+
| 2 | tests/unit/xxx/test_MyService.py | test_MyService | test_parse_raises_on_empty | TypeError | argument cannot be None |
|
|
109
|
+
|
|
110
|
+
### 失败堆栈(如有)
|
|
111
|
+
#### 1. test_create_with_valid_data
|
|
112
|
+
```
|
|
113
|
+
E assert result.id is not None
|
|
114
|
+
E assert None is not None
|
|
115
|
+
tests/unit/xxx/test_MyService.py:15
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 结论
|
|
119
|
+
- [全部通过] → 建议回到覆盖率分析阶段
|
|
120
|
+
- [有失败] → 建议进入用例修复阶段,共 X 个失败需修复
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 决策
|
|
126
|
+
|
|
127
|
+
| 条件 | 动作 |
|
|
128
|
+
|------|------|
|
|
129
|
+
| 全部通过(failed=0, error=0) | 输出"全部通过",回到 coverage-analyze |
|
|
130
|
+
| 有失败(failed>0 或 error>0) | 输出失败详情,交给 pytest-case-fix |
|
|
131
|
+
|
|
132
|
+
## 失败处理
|
|
133
|
+
|
|
134
|
+
| 场景 | 处理方式 |
|
|
135
|
+
|------|---------|
|
|
136
|
+
| 测试目录不存在 | 输出"测试目录不存在",提示需要先创建用例 |
|
|
137
|
+
| pytest 执行错误(非测试失败) | 退出,输出错误信息 |
|
|
138
|
+
| 无测试文件 | 输出"无测试文件",通过率 0% |
|
|
139
|
+
| pytest 超时 | 退出,提示测试执行超时,建议检查 hang 住的用例或增加 timeout |
|
|
140
|
+
|
|
141
|
+
## 一定要做
|
|
142
|
+
|
|
143
|
+
1. 必须使用传入的 test_dir 运行测试,并根据 test_type 选择 marker
|
|
144
|
+
2. 必须使用 -v 输出详细结果
|
|
145
|
+
3. 必须提取每个失败用例的详细信息
|
|
146
|
+
4. 必须输出通过率
|
|
147
|
+
5. 如果指定了 test_files,只运行指定文件
|
|
148
|
+
|
|
149
|
+
## 一定不要做
|
|
150
|
+
|
|
151
|
+
1. 不要修改测试文件或源码
|
|
152
|
+
2. 不要跳过失败的用例
|
|
153
|
+
3. 不要混合 unit 和 integration 的测试
|
|
154
|
+
4. 不要忽略 pytest 执行错误
|
|
155
|
+
5. 不要使用 --tb=long(堆栈过长影响分析)
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pytest-sample
|
|
3
|
+
description: |
|
|
4
|
+
在当前工程 src/ 下创建 pytest-sample 目录,注入一批 demo 类代码。
|
|
5
|
+
覆盖纯函数、HTTP Mock、DB Mock、文件系统、时间依赖、随机值、环境变量、状态机等多种测试场景。
|
|
6
|
+
demo 代码中故意注入了 15 个 bug(分 3 个难度梯度),用于触发测试代理的 create→test→fix 循环。
|
|
7
|
+
适用:首次使用 pyut/pyit agent 前的演示验证、测试 agent 流程的端到端测试。
|
|
8
|
+
不适用:生产代码、非测试目的的代码生成。
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Demo 样例代码注入
|
|
12
|
+
|
|
13
|
+
## 工作流模式
|
|
14
|
+
|
|
15
|
+
本 Skill 采用 **顺序执行** 工作流:
|
|
16
|
+
|
|
17
|
+
1. **创建目录**:在 src/ 下创建 pytest-sample 包目录
|
|
18
|
+
2. **写入文件**:从 references/src/pytest-sample/ 读取模板,写入到 src/pytest-sample/
|
|
19
|
+
3. **验证**:检查所有文件语法正确
|
|
20
|
+
|
|
21
|
+
## 输入
|
|
22
|
+
|
|
23
|
+
| 参数 | 必填 | 类型 | 说明 |
|
|
24
|
+
|------|------|------|------|
|
|
25
|
+
| 无 | - | - | 自动在当前工程 src/ 下创建 |
|
|
26
|
+
|
|
27
|
+
## 输出
|
|
28
|
+
|
|
29
|
+
- src/pytest-sample/ 目录及 7 个文件
|
|
30
|
+
- 各文件覆盖的测试场景清单
|
|
31
|
+
- 故意 bug 清单及难度分级
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 阶段一:创建目录
|
|
36
|
+
|
|
37
|
+
**操作**:创建 `src/pytest-sample/` 目录
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 阶段二:写入文件
|
|
42
|
+
|
|
43
|
+
从 `references/src/pytest-sample/` 目录读取以下模板文件,写入到 `src/pytest-sample/`:
|
|
44
|
+
|
|
45
|
+
| 文件 | 覆盖场景 |
|
|
46
|
+
|------|---------|
|
|
47
|
+
| __init__.py | 包初始化 |
|
|
48
|
+
| Calculator.py | 纯函数、分支(if/elif)、异常(raise)、边界值、参数化 |
|
|
49
|
+
| UserService.py | HTTP 请求(Mock)、数据库(Mock)、时间依赖(patch datetime)、验证逻辑 |
|
|
50
|
+
| FileProcessor.py | 文件系统(tmp_path)、JSON 解析、文件不存在异常、目录操作 |
|
|
51
|
+
| TokenGenerator.py | 随机值(patch random)、时间(patch time)、哈希、批量生成、边界检查 |
|
|
52
|
+
| ConfigManager.py | 环境变量(monkeypatch)、单例模式、类型转换、默认值 |
|
|
53
|
+
| OrderService.py | 复杂业务逻辑、状态机、多依赖、折扣计算(分支)、外部服务(Mock) |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 阶段三:验证
|
|
58
|
+
|
|
59
|
+
**操作**:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
uv run python -m py_compile src/pytest-sample/*.py
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**决策**:
|
|
66
|
+
|
|
67
|
+
| 条件 | 动作 |
|
|
68
|
+
|------|------|
|
|
69
|
+
| 全部语法正确 | 输出创建报告 |
|
|
70
|
+
| 有语法错误 | 修复后重新验证 |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 故意 Bug 设计
|
|
75
|
+
|
|
76
|
+
demo 代码中故意注入了 15 个 bug,分为 3 个难度梯度,用于尽可能触发测试代理的循环迭代。
|
|
77
|
+
|
|
78
|
+
### Easy 难度(基础测试即可发现)
|
|
79
|
+
|
|
80
|
+
| # | 文件 | 方法 | Bug 描述 | 触发方式 |
|
|
81
|
+
|---|------|------|---------|---------|
|
|
82
|
+
| 1 | Calculator.py | clamp | min/max 返回值互换 | 断言 clamp(0,1,10)==1 |
|
|
83
|
+
| 2 | FileProcessor.py | write_file | 返回 len(content) 而非文件大小 | 写入多字节字符后断言 |
|
|
84
|
+
| 3 | UserService.py | validate_email | TLD 正则 {2,}→{2} 拒绝 .com | 断言 validate_email("a@b.com")==True |
|
|
85
|
+
|
|
86
|
+
### Medium 难度(需边界值/序列测试)
|
|
87
|
+
|
|
88
|
+
| # | 文件 | 方法 | Bug 描述 | 触发方式 |
|
|
89
|
+
|---|------|------|---------|---------|
|
|
90
|
+
| 4 | Calculator.py | is_prime | sqrt+1→sqrt 漏检平方数 | 断言 is_prime(9)==False |
|
|
91
|
+
| 5 | Calculator.py | fibonacci | range off-by-one | 断言 fibonacci(3)==2 |
|
|
92
|
+
| 6 | FileProcessor.py | count_lines | 缺少 strip() 计入空白行 | 带首尾空行的文件断言 |
|
|
93
|
+
| 7 | OrderService.py | _get_discount | >= → > 边界 | 断言 1000 元折扣为 10% |
|
|
94
|
+
| 8 | OrderService.py | _get_tax | >= → > 边界 | 断言 500 元税率为 8% |
|
|
95
|
+
| 9 | TokenGenerator.py | generate_uuid_like | 末段 12→11 字符 | UUID 格式正则验证 |
|
|
96
|
+
|
|
97
|
+
### Hard 难度(需深入理解/非标准输入测试)
|
|
98
|
+
|
|
99
|
+
| # | 文件 | 方法 | Bug 描述 | 触发方式 |
|
|
100
|
+
|---|------|------|---------|---------|
|
|
101
|
+
| 10 | ConfigManager.py | get_bool | 反转 truthy 逻辑,非标准字符串返回 True | 断言 get_bool(key, "unknown")==False |
|
|
102
|
+
| 11 | ConfigManager.py | reset | 单例 _instance 未重置 | reset 后断言新实例 id 不同 |
|
|
103
|
+
| 12 | OrderService.py | TRANSITIONS | created→delivered 非法跳转 | 断言该转换抛出 ValueError |
|
|
104
|
+
| 13 | UserService.py | search_users | 返回完整 JSON 而非 results 字段 | 断言返回值为 list |
|
|
105
|
+
| 14 | OrderService.py | create_order | 缺少 user_id 类型校验 | 传入字符串 user_id 断言 ValueError |
|
|
106
|
+
| 15 | TokenGenerator.py | generate_token_with_timestamp | 时间戳含小数点 | 正则验证 token 格式 |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 输出格式
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
## Demo 样例代码创建报告
|
|
114
|
+
|
|
115
|
+
### 创建文件
|
|
116
|
+
| 文件路径 | 类名 | 覆盖场景 |
|
|
117
|
+
|---------|------|---------|
|
|
118
|
+
| src/pytest-sample/__init__.py | - | 包初始化 |
|
|
119
|
+
| src/pytest-sample/Calculator.py | Calculator | 纯函数、分支、异常、边界值 |
|
|
120
|
+
| src/pytest-sample/UserService.py | UserService | HTTP Mock、DB Mock、时间 patch |
|
|
121
|
+
| src/pytest-sample/FileProcessor.py | FileProcessor | 文件系统、JSON、异常 |
|
|
122
|
+
| src/pytest-sample/TokenGenerator.py | TokenGenerator | 随机 Mock、时间 Mock、哈希 |
|
|
123
|
+
| src/pytest-sample/ConfigManager.py | ConfigManager | 环境变量、单例、类型转换 |
|
|
124
|
+
| src/pytest-sample/OrderService.py | OrderService | 状态机、多依赖、折扣计算 |
|
|
125
|
+
|
|
126
|
+
### 故意 Bug 统计
|
|
127
|
+
- Easy: 3 个(基础测试可发现)
|
|
128
|
+
- Medium: 6 个(需边界值/序列测试)
|
|
129
|
+
- Hard: 6 个(需深入理解/非标准输入)
|
|
130
|
+
- 总计: 15 个
|
|
131
|
+
|
|
132
|
+
### 使用方式
|
|
133
|
+
1. 单元测试: /pyut src/pytest-sample
|
|
134
|
+
2. 集成测试: /pyit src/pytest-sample
|
|
135
|
+
|
|
136
|
+
### 场景覆盖说明
|
|
137
|
+
- 纯函数测试: Calculator.add, Calculator.is_prime
|
|
138
|
+
- 分支覆盖: Calculator.clamp, OrderService._get_discount
|
|
139
|
+
- 异常路径: Calculator.divide(0), UserService.create_user(无email)
|
|
140
|
+
- 边界值: Calculator.factorial(0), TokenGenerator.generate_token(1)
|
|
141
|
+
- HTTP Mock: UserService.create_user
|
|
142
|
+
- DB Mock: UserService.get_user, OrderService.create_order
|
|
143
|
+
- 文件系统: FileProcessor.read_file, FileProcessor.write_file
|
|
144
|
+
- 时间 Mock: UserService.update_last_login, OrderService.create_order
|
|
145
|
+
- 随机 Mock: TokenGenerator.generate_token
|
|
146
|
+
- 环境变量: ConfigManager.get_database_url
|
|
147
|
+
- 状态机: OrderService.update_status
|
|
148
|
+
- 参数化: Calculator.is_prime, Calculator.factorial
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 一定要做
|
|
152
|
+
|
|
153
|
+
1. 必须在 src/pytest-sample/ 目录下创建文件
|
|
154
|
+
2. 必须从 references/src/pytest-sample/ 读取模板内容写入
|
|
155
|
+
3. 创建后必须验证语法正确
|
|
156
|
+
4. 必须输出场景覆盖说明
|
|
157
|
+
5. 必须保留 demo 中的故意 bug,不要修复
|
|
158
|
+
|
|
159
|
+
## 一定不要做
|
|
160
|
+
|
|
161
|
+
1. 不要修改 src/ 下已有的其他文件
|
|
162
|
+
2. 不要在 demo 代码中导入项目特定的三方库
|
|
163
|
+
3. 不要跳过语法验证
|
|
164
|
+
4. 不要修复 demo 中的故意 bug(它们是设计意图)
|