ccgx-workflow 1.0.0 → 1.0.1
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/README.md +37 -5
- package/README.zh-CN.md +35 -5
- package/dist/cli.mjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/shared/{ccgx-workflow.WgUzkiC3.mjs → ccgx-workflow.SJPbUy5_.mjs} +17 -110
- package/package.json +2 -1
- package/templates/commands/agents/phase-runner.md +321 -321
- package/templates/commands/autonomous.md +792 -792
- package/templates/commands/cancel.md +132 -132
- package/templates/commands/debug.md +226 -226
- package/templates/commands/status.md +206 -206
- package/templates/commands/team.md +484 -0
- package/templates/hooks/ccg-session-state.cjs +510 -510
- package/templates/scripts/ccg-phase-runner-launcher.mjs +467 -467
- package/templates/scripts/invoke-model.mjs +64 -0
- package/templates/skills/domains/ai/SKILL.md +35 -35
- package/templates/skills/domains/ai/agent-dev.md +242 -242
- package/templates/skills/domains/ai/llm-security.md +288 -288
- package/templates/skills/domains/ai/rag-system.md +542 -542
- package/templates/skills/domains/architecture/SKILL.md +43 -43
- package/templates/skills/domains/architecture/api-design.md +225 -225
- package/templates/skills/domains/architecture/cloud-native.md +285 -285
- package/templates/skills/domains/architecture/security-arch.md +297 -297
- package/templates/skills/domains/data-engineering/SKILL.md +208 -208
- package/templates/skills/domains/development/SKILL.md +47 -47
- package/templates/skills/domains/development/cpp.md +246 -246
- package/templates/skills/domains/development/go.md +323 -323
- package/templates/skills/domains/development/java.md +277 -277
- package/templates/skills/domains/development/python.md +288 -288
- package/templates/skills/domains/development/rust.md +313 -313
- package/templates/skills/domains/development/shell.md +313 -313
- package/templates/skills/domains/development/typescript.md +277 -277
- package/templates/skills/domains/devops/SKILL.md +40 -40
- package/templates/skills/domains/devops/database.md +217 -217
- package/templates/skills/domains/devops/devsecops.md +198 -198
- package/templates/skills/domains/devops/git-workflow.md +181 -181
- package/templates/skills/domains/devops/testing.md +283 -283
- package/templates/skills/domains/frontend-design/SKILL.md +244 -244
- package/templates/skills/domains/frontend-design/claymorphism/SKILL.md +121 -121
- package/templates/skills/domains/frontend-design/component-patterns.md +202 -202
- package/templates/skills/domains/frontend-design/glassmorphism/SKILL.md +142 -142
- package/templates/skills/domains/frontend-design/liquid-glass/SKILL.md +139 -139
- package/templates/skills/domains/frontend-design/neubrutalism/SKILL.md +145 -145
- package/templates/skills/domains/frontend-design/state-management.md +680 -680
- package/templates/skills/domains/frontend-design/ui-aesthetics.md +110 -110
- package/templates/skills/domains/frontend-design/ux-principles.md +156 -156
- package/templates/skills/domains/infrastructure/SKILL.md +201 -201
- package/templates/skills/domains/mobile/SKILL.md +225 -225
- package/templates/skills/domains/orchestration/SKILL.md +30 -30
- package/templates/skills/domains/orchestration/multi-agent.md +228 -228
- package/templates/skills/domains/security/SKILL.md +73 -73
- package/templates/skills/domains/security/blue-team.md +436 -436
- package/templates/skills/domains/security/code-audit.md +265 -265
- package/templates/skills/domains/security/pentest.md +226 -226
- package/templates/skills/domains/security/red-team.md +374 -374
- package/templates/skills/domains/security/threat-intel.md +372 -372
- package/templates/skills/domains/security/vuln-research.md +369 -369
- package/templates/skills/tools/lib/shared.js +98 -98
- package/templates/skills/tools/override-refusal/SKILL.md +53 -53
- package/templates/skills/tools/override-refusal/scripts/refusal_rewriter.js +226 -226
|
@@ -1,283 +1,283 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: testing
|
|
3
|
-
description: 软件测试。单元测试、集成测试、TDD、测试框架。当用户提到测试、单元测试、pytest、Jest、mock、TDD时使用。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# 🔧 炼器秘典 · 软件测试
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## 测试金字塔
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
/\
|
|
13
|
-
/ \ E2E 测试 (少)
|
|
14
|
-
/----\
|
|
15
|
-
/ \ 集成测试 (中)
|
|
16
|
-
/--------\
|
|
17
|
-
/ \ 单元测试 (多)
|
|
18
|
-
--------------
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Python (pytest)
|
|
22
|
-
|
|
23
|
-
```python
|
|
24
|
-
import pytest
|
|
25
|
-
from myapp import calculate, UserService
|
|
26
|
-
|
|
27
|
-
# 基础测试
|
|
28
|
-
def test_add():
|
|
29
|
-
assert calculate.add(1, 2) == 3
|
|
30
|
-
|
|
31
|
-
# 参数化
|
|
32
|
-
@pytest.mark.parametrize("a,b,expected", [
|
|
33
|
-
(1, 2, 3),
|
|
34
|
-
(0, 0, 0),
|
|
35
|
-
(-1, 1, 0),
|
|
36
|
-
])
|
|
37
|
-
def test_add_params(a, b, expected):
|
|
38
|
-
assert calculate.add(a, b) == expected
|
|
39
|
-
|
|
40
|
-
# Fixture
|
|
41
|
-
@pytest.fixture
|
|
42
|
-
def user_service():
|
|
43
|
-
service = UserService()
|
|
44
|
-
yield service
|
|
45
|
-
service.cleanup()
|
|
46
|
-
|
|
47
|
-
def test_create_user(user_service):
|
|
48
|
-
user = user_service.create("test")
|
|
49
|
-
assert user.name == "test"
|
|
50
|
-
|
|
51
|
-
# Mock
|
|
52
|
-
from unittest.mock import Mock, patch
|
|
53
|
-
|
|
54
|
-
@patch('myapp.requests.get')
|
|
55
|
-
def test_fetch(mock_get):
|
|
56
|
-
mock_get.return_value.json.return_value = {"id": 1}
|
|
57
|
-
result = fetch_user(1)
|
|
58
|
-
assert result["id"] == 1
|
|
59
|
-
|
|
60
|
-
# 异步测试
|
|
61
|
-
@pytest.mark.asyncio
|
|
62
|
-
async def test_async_fetch():
|
|
63
|
-
result = await async_fetch()
|
|
64
|
-
assert result is not None
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### 运行命令
|
|
68
|
-
```bash
|
|
69
|
-
pytest # 运行所有
|
|
70
|
-
pytest test_file.py # 指定文件
|
|
71
|
-
pytest -k "test_add" # 匹配名称
|
|
72
|
-
pytest -v # 详细输出
|
|
73
|
-
pytest --cov=myapp # 覆盖率
|
|
74
|
-
pytest -x # 失败即停
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## JavaScript (Jest/Vitest)
|
|
78
|
-
|
|
79
|
-
```javascript
|
|
80
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
81
|
-
|
|
82
|
-
// 基础测试
|
|
83
|
-
describe('add', () => {
|
|
84
|
-
it('should add two numbers', () => {
|
|
85
|
-
expect(add(1, 2)).toBe(3);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it.each([
|
|
89
|
-
[1, 2, 3],
|
|
90
|
-
[0, 0, 0],
|
|
91
|
-
[-1, 1, 0],
|
|
92
|
-
])('add(%i, %i) = %i', (a, b, expected) => {
|
|
93
|
-
expect(add(a, b)).toBe(expected);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Mock
|
|
98
|
-
vi.mock('./api', () => ({
|
|
99
|
-
getUser: vi.fn().mockResolvedValue({ id: 1, name: 'test' })
|
|
100
|
-
}));
|
|
101
|
-
|
|
102
|
-
it('should fetch user', async () => {
|
|
103
|
-
const user = await fetchUser(1);
|
|
104
|
-
expect(user.name).toBe('test');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Spy
|
|
108
|
-
const spy = vi.spyOn(console, 'log');
|
|
109
|
-
doSomething();
|
|
110
|
-
expect(spy).toHaveBeenCalledWith('message');
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Go (testing)
|
|
114
|
-
|
|
115
|
-
```go
|
|
116
|
-
package main
|
|
117
|
-
|
|
118
|
-
import (
|
|
119
|
-
"testing"
|
|
120
|
-
"github.com/stretchr/testify/assert"
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
func TestAdd(t *testing.T) {
|
|
124
|
-
result := Add(1, 2)
|
|
125
|
-
assert.Equal(t, 3, result)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// 表驱动测试
|
|
129
|
-
func TestAddTable(t *testing.T) {
|
|
130
|
-
tests := []struct {
|
|
131
|
-
name string
|
|
132
|
-
a, b int
|
|
133
|
-
expected int
|
|
134
|
-
}{
|
|
135
|
-
{"positive", 1, 2, 3},
|
|
136
|
-
{"zero", 0, 0, 0},
|
|
137
|
-
{"negative", -1, 1, 0},
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
for _, tt := range tests {
|
|
141
|
-
t.Run(tt.name, func(t *testing.T) {
|
|
142
|
-
assert.Equal(t, tt.expected, Add(tt.a, tt.b))
|
|
143
|
-
})
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Benchmark
|
|
148
|
-
func BenchmarkAdd(b *testing.B) {
|
|
149
|
-
for i := 0; i < b.N; i++ {
|
|
150
|
-
Add(1, 2)
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## 测试原则
|
|
156
|
-
|
|
157
|
-
```yaml
|
|
158
|
-
FIRST:
|
|
159
|
-
- Fast: 快速执行
|
|
160
|
-
- Independent: 相互独立
|
|
161
|
-
- Repeatable: 可重复
|
|
162
|
-
- Self-validating: 自验证
|
|
163
|
-
- Timely: 及时编写
|
|
164
|
-
|
|
165
|
-
AAA:
|
|
166
|
-
- Arrange: 准备数据
|
|
167
|
-
- Act: 执行操作
|
|
168
|
-
- Assert: 验证结果
|
|
169
|
-
|
|
170
|
-
原则:
|
|
171
|
-
- 每个测试只验证一件事
|
|
172
|
-
- 测试边界条件
|
|
173
|
-
- 测试异常情况
|
|
174
|
-
- 避免测试实现细节
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## TDD 流程
|
|
178
|
-
|
|
179
|
-
```
|
|
180
|
-
红 → 绿 → 重构
|
|
181
|
-
|
|
182
|
-
1. 红: 写一个失败的测试
|
|
183
|
-
2. 绿: 写最少代码让测试通过
|
|
184
|
-
3. 重构: 优化代码,保持测试通过
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
## 测试策略(源自 testing-strategy)
|
|
190
|
-
|
|
191
|
-
### 测试金字塔比例
|
|
192
|
-
|
|
193
|
-
| 层级 | 占比 | 执行时间 | 成本 |
|
|
194
|
-
|------|------|----------|------|
|
|
195
|
-
| 单元测试 | 70% | <1s | 低 |
|
|
196
|
-
| 集成测试 | 20% | 1-10s | 中 |
|
|
197
|
-
| E2E测试 | 10% | 10s-5m | 高 |
|
|
198
|
-
|
|
199
|
-
### 测试左移 Checklist
|
|
200
|
-
|
|
201
|
-
```yaml
|
|
202
|
-
需求阶段: 可测试性评审、验收标准定义、测试用例设计
|
|
203
|
-
开发阶段: TDD、单元测试同步编写、代码审查包含测试
|
|
204
|
-
提交阶段: Pre-commit Hook、本地测试必过、静态分析
|
|
205
|
-
CI阶段: 自动化测试、覆盖率门禁、性能基准测试
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### 契约测试要点
|
|
209
|
-
|
|
210
|
-
- 消费者驱动契约 (CDC):Consumer 定义期望 → Provider 验证契约
|
|
211
|
-
- 工具:Pact(多语言)、Spring Cloud Contract(Java)
|
|
212
|
-
- 核心:Provider API <-> Contract <-> Consumer,双方独立验证
|
|
213
|
-
|
|
214
|
-
### 覆盖率策略
|
|
215
|
-
|
|
216
|
-
```yaml
|
|
217
|
-
类型: 行覆盖率、分支覆盖率、函数覆盖率、语句覆盖率
|
|
218
|
-
门禁: 全局 ≥80%,核心模块 ≥90%
|
|
219
|
-
排除: tests/、migrations/、__init__.py、config 文件
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### 变异测试
|
|
223
|
-
|
|
224
|
-
- 修改源码(变异体)验证测试是否能捕获
|
|
225
|
-
- 工具:Stryker (JS)、Pitest (Java)
|
|
226
|
-
- 阈值:high 80% / low 60% / break 50%
|
|
227
|
-
|
|
228
|
-
### 测试最佳实践
|
|
229
|
-
|
|
230
|
-
- AAA 模式:Arrange → Act → Assert
|
|
231
|
-
- 命名:`should [预期行为] when [条件]`
|
|
232
|
-
- 单一职责:每个测试只验证一件事
|
|
233
|
-
- 数据隔离:Fixture/Factory 模式,每测试独立实例
|
|
234
|
-
- 并行执行:Jest `maxWorkers: '50%'`、pytest `-n auto`
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
## E2E 测试(源自 e2e-testing)
|
|
239
|
-
|
|
240
|
-
### Playwright vs Cypress
|
|
241
|
-
|
|
242
|
-
| 特性 | Playwright | Cypress |
|
|
243
|
-
|------|-----------|---------|
|
|
244
|
-
| 多浏览器 | Chromium/Firefox/WebKit | Chromium/Firefox/Edge |
|
|
245
|
-
| 多标签页/iframe | 原生支持 | 有限 |
|
|
246
|
-
| 并行执行 | 原生支持 | 需付费 |
|
|
247
|
-
| 调试体验 | 一般 | 优秀 |
|
|
248
|
-
|
|
249
|
-
### 选择器优先级
|
|
250
|
-
|
|
251
|
-
```
|
|
252
|
-
1. data-testid (推荐)
|
|
253
|
-
2. role + accessible name
|
|
254
|
-
3. 稳定的 class/id
|
|
255
|
-
4. 文本内容 (谨慎)
|
|
256
|
-
5. CSS/XPath (避免)
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### E2E Checklist
|
|
260
|
-
|
|
261
|
-
```yaml
|
|
262
|
-
架构:
|
|
263
|
-
- 页面对象模式 (POM) 封装页面操作
|
|
264
|
-
- 测试独立性:通过 API 准备数据,不依赖其他测试
|
|
265
|
-
- 智能等待:waitForSelector/waitForResponse,禁止 waitForTimeout
|
|
266
|
-
|
|
267
|
-
网络:
|
|
268
|
-
- Mock API:page.route() / cy.intercept() 隔离后端
|
|
269
|
-
- 等待响应:waitForResponse 确认数据加载
|
|
270
|
-
|
|
271
|
-
可视化回归:
|
|
272
|
-
- Playwright: toHaveScreenshot() + mask 动态内容
|
|
273
|
-
- Percy/Chromatic: 云端截图对比
|
|
274
|
-
|
|
275
|
-
认证:
|
|
276
|
-
- Playwright: storageState 复用登录态
|
|
277
|
-
- Cypress: cy.session() 缓存会话
|
|
278
|
-
|
|
279
|
-
CI集成:
|
|
280
|
-
- retries: CI 环境 2 次重试
|
|
281
|
-
- artifacts: 失败时保存截图/视频/trace
|
|
282
|
-
```
|
|
283
|
-
|
|
1
|
+
---
|
|
2
|
+
name: testing
|
|
3
|
+
description: 软件测试。单元测试、集成测试、TDD、测试框架。当用户提到测试、单元测试、pytest、Jest、mock、TDD时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 🔧 炼器秘典 · 软件测试
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## 测试金字塔
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/\
|
|
13
|
+
/ \ E2E 测试 (少)
|
|
14
|
+
/----\
|
|
15
|
+
/ \ 集成测试 (中)
|
|
16
|
+
/--------\
|
|
17
|
+
/ \ 单元测试 (多)
|
|
18
|
+
--------------
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Python (pytest)
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import pytest
|
|
25
|
+
from myapp import calculate, UserService
|
|
26
|
+
|
|
27
|
+
# 基础测试
|
|
28
|
+
def test_add():
|
|
29
|
+
assert calculate.add(1, 2) == 3
|
|
30
|
+
|
|
31
|
+
# 参数化
|
|
32
|
+
@pytest.mark.parametrize("a,b,expected", [
|
|
33
|
+
(1, 2, 3),
|
|
34
|
+
(0, 0, 0),
|
|
35
|
+
(-1, 1, 0),
|
|
36
|
+
])
|
|
37
|
+
def test_add_params(a, b, expected):
|
|
38
|
+
assert calculate.add(a, b) == expected
|
|
39
|
+
|
|
40
|
+
# Fixture
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def user_service():
|
|
43
|
+
service = UserService()
|
|
44
|
+
yield service
|
|
45
|
+
service.cleanup()
|
|
46
|
+
|
|
47
|
+
def test_create_user(user_service):
|
|
48
|
+
user = user_service.create("test")
|
|
49
|
+
assert user.name == "test"
|
|
50
|
+
|
|
51
|
+
# Mock
|
|
52
|
+
from unittest.mock import Mock, patch
|
|
53
|
+
|
|
54
|
+
@patch('myapp.requests.get')
|
|
55
|
+
def test_fetch(mock_get):
|
|
56
|
+
mock_get.return_value.json.return_value = {"id": 1}
|
|
57
|
+
result = fetch_user(1)
|
|
58
|
+
assert result["id"] == 1
|
|
59
|
+
|
|
60
|
+
# 异步测试
|
|
61
|
+
@pytest.mark.asyncio
|
|
62
|
+
async def test_async_fetch():
|
|
63
|
+
result = await async_fetch()
|
|
64
|
+
assert result is not None
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 运行命令
|
|
68
|
+
```bash
|
|
69
|
+
pytest # 运行所有
|
|
70
|
+
pytest test_file.py # 指定文件
|
|
71
|
+
pytest -k "test_add" # 匹配名称
|
|
72
|
+
pytest -v # 详细输出
|
|
73
|
+
pytest --cov=myapp # 覆盖率
|
|
74
|
+
pytest -x # 失败即停
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## JavaScript (Jest/Vitest)
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
81
|
+
|
|
82
|
+
// 基础测试
|
|
83
|
+
describe('add', () => {
|
|
84
|
+
it('should add two numbers', () => {
|
|
85
|
+
expect(add(1, 2)).toBe(3);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it.each([
|
|
89
|
+
[1, 2, 3],
|
|
90
|
+
[0, 0, 0],
|
|
91
|
+
[-1, 1, 0],
|
|
92
|
+
])('add(%i, %i) = %i', (a, b, expected) => {
|
|
93
|
+
expect(add(a, b)).toBe(expected);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Mock
|
|
98
|
+
vi.mock('./api', () => ({
|
|
99
|
+
getUser: vi.fn().mockResolvedValue({ id: 1, name: 'test' })
|
|
100
|
+
}));
|
|
101
|
+
|
|
102
|
+
it('should fetch user', async () => {
|
|
103
|
+
const user = await fetchUser(1);
|
|
104
|
+
expect(user.name).toBe('test');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Spy
|
|
108
|
+
const spy = vi.spyOn(console, 'log');
|
|
109
|
+
doSomething();
|
|
110
|
+
expect(spy).toHaveBeenCalledWith('message');
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Go (testing)
|
|
114
|
+
|
|
115
|
+
```go
|
|
116
|
+
package main
|
|
117
|
+
|
|
118
|
+
import (
|
|
119
|
+
"testing"
|
|
120
|
+
"github.com/stretchr/testify/assert"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
func TestAdd(t *testing.T) {
|
|
124
|
+
result := Add(1, 2)
|
|
125
|
+
assert.Equal(t, 3, result)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 表驱动测试
|
|
129
|
+
func TestAddTable(t *testing.T) {
|
|
130
|
+
tests := []struct {
|
|
131
|
+
name string
|
|
132
|
+
a, b int
|
|
133
|
+
expected int
|
|
134
|
+
}{
|
|
135
|
+
{"positive", 1, 2, 3},
|
|
136
|
+
{"zero", 0, 0, 0},
|
|
137
|
+
{"negative", -1, 1, 0},
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
for _, tt := range tests {
|
|
141
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
142
|
+
assert.Equal(t, tt.expected, Add(tt.a, tt.b))
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Benchmark
|
|
148
|
+
func BenchmarkAdd(b *testing.B) {
|
|
149
|
+
for i := 0; i < b.N; i++ {
|
|
150
|
+
Add(1, 2)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## 测试原则
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
FIRST:
|
|
159
|
+
- Fast: 快速执行
|
|
160
|
+
- Independent: 相互独立
|
|
161
|
+
- Repeatable: 可重复
|
|
162
|
+
- Self-validating: 自验证
|
|
163
|
+
- Timely: 及时编写
|
|
164
|
+
|
|
165
|
+
AAA:
|
|
166
|
+
- Arrange: 准备数据
|
|
167
|
+
- Act: 执行操作
|
|
168
|
+
- Assert: 验证结果
|
|
169
|
+
|
|
170
|
+
原则:
|
|
171
|
+
- 每个测试只验证一件事
|
|
172
|
+
- 测试边界条件
|
|
173
|
+
- 测试异常情况
|
|
174
|
+
- 避免测试实现细节
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## TDD 流程
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
红 → 绿 → 重构
|
|
181
|
+
|
|
182
|
+
1. 红: 写一个失败的测试
|
|
183
|
+
2. 绿: 写最少代码让测试通过
|
|
184
|
+
3. 重构: 优化代码,保持测试通过
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 测试策略(源自 testing-strategy)
|
|
190
|
+
|
|
191
|
+
### 测试金字塔比例
|
|
192
|
+
|
|
193
|
+
| 层级 | 占比 | 执行时间 | 成本 |
|
|
194
|
+
|------|------|----------|------|
|
|
195
|
+
| 单元测试 | 70% | <1s | 低 |
|
|
196
|
+
| 集成测试 | 20% | 1-10s | 中 |
|
|
197
|
+
| E2E测试 | 10% | 10s-5m | 高 |
|
|
198
|
+
|
|
199
|
+
### 测试左移 Checklist
|
|
200
|
+
|
|
201
|
+
```yaml
|
|
202
|
+
需求阶段: 可测试性评审、验收标准定义、测试用例设计
|
|
203
|
+
开发阶段: TDD、单元测试同步编写、代码审查包含测试
|
|
204
|
+
提交阶段: Pre-commit Hook、本地测试必过、静态分析
|
|
205
|
+
CI阶段: 自动化测试、覆盖率门禁、性能基准测试
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 契约测试要点
|
|
209
|
+
|
|
210
|
+
- 消费者驱动契约 (CDC):Consumer 定义期望 → Provider 验证契约
|
|
211
|
+
- 工具:Pact(多语言)、Spring Cloud Contract(Java)
|
|
212
|
+
- 核心:Provider API <-> Contract <-> Consumer,双方独立验证
|
|
213
|
+
|
|
214
|
+
### 覆盖率策略
|
|
215
|
+
|
|
216
|
+
```yaml
|
|
217
|
+
类型: 行覆盖率、分支覆盖率、函数覆盖率、语句覆盖率
|
|
218
|
+
门禁: 全局 ≥80%,核心模块 ≥90%
|
|
219
|
+
排除: tests/、migrations/、__init__.py、config 文件
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### 变异测试
|
|
223
|
+
|
|
224
|
+
- 修改源码(变异体)验证测试是否能捕获
|
|
225
|
+
- 工具:Stryker (JS)、Pitest (Java)
|
|
226
|
+
- 阈值:high 80% / low 60% / break 50%
|
|
227
|
+
|
|
228
|
+
### 测试最佳实践
|
|
229
|
+
|
|
230
|
+
- AAA 模式:Arrange → Act → Assert
|
|
231
|
+
- 命名:`should [预期行为] when [条件]`
|
|
232
|
+
- 单一职责:每个测试只验证一件事
|
|
233
|
+
- 数据隔离:Fixture/Factory 模式,每测试独立实例
|
|
234
|
+
- 并行执行:Jest `maxWorkers: '50%'`、pytest `-n auto`
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## E2E 测试(源自 e2e-testing)
|
|
239
|
+
|
|
240
|
+
### Playwright vs Cypress
|
|
241
|
+
|
|
242
|
+
| 特性 | Playwright | Cypress |
|
|
243
|
+
|------|-----------|---------|
|
|
244
|
+
| 多浏览器 | Chromium/Firefox/WebKit | Chromium/Firefox/Edge |
|
|
245
|
+
| 多标签页/iframe | 原生支持 | 有限 |
|
|
246
|
+
| 并行执行 | 原生支持 | 需付费 |
|
|
247
|
+
| 调试体验 | 一般 | 优秀 |
|
|
248
|
+
|
|
249
|
+
### 选择器优先级
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
1. data-testid (推荐)
|
|
253
|
+
2. role + accessible name
|
|
254
|
+
3. 稳定的 class/id
|
|
255
|
+
4. 文本内容 (谨慎)
|
|
256
|
+
5. CSS/XPath (避免)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### E2E Checklist
|
|
260
|
+
|
|
261
|
+
```yaml
|
|
262
|
+
架构:
|
|
263
|
+
- 页面对象模式 (POM) 封装页面操作
|
|
264
|
+
- 测试独立性:通过 API 准备数据,不依赖其他测试
|
|
265
|
+
- 智能等待:waitForSelector/waitForResponse,禁止 waitForTimeout
|
|
266
|
+
|
|
267
|
+
网络:
|
|
268
|
+
- Mock API:page.route() / cy.intercept() 隔离后端
|
|
269
|
+
- 等待响应:waitForResponse 确认数据加载
|
|
270
|
+
|
|
271
|
+
可视化回归:
|
|
272
|
+
- Playwright: toHaveScreenshot() + mask 动态内容
|
|
273
|
+
- Percy/Chromatic: 云端截图对比
|
|
274
|
+
|
|
275
|
+
认证:
|
|
276
|
+
- Playwright: storageState 复用登录态
|
|
277
|
+
- Cypress: cy.session() 缓存会话
|
|
278
|
+
|
|
279
|
+
CI集成:
|
|
280
|
+
- retries: CI 环境 2 次重试
|
|
281
|
+
- artifacts: 失败时保存截图/视频/trace
|
|
282
|
+
```
|
|
283
|
+
|