zco-claude 0.0.8__py3-none-any.whl

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.
Files changed (34) hide show
  1. ClaudeSettings/DOT.claudeignore +7 -0
  2. ClaudeSettings/README.md +100 -0
  3. ClaudeSettings/commands/generate_changelog.sh +49 -0
  4. ClaudeSettings/commands/show_env +92 -0
  5. ClaudeSettings/commands/zco-clean +164 -0
  6. ClaudeSettings/commands/zco-git-summary +15 -0
  7. ClaudeSettings/commands/zco-git-tag +42 -0
  8. ClaudeSettings/hooks/CHANGELOG.md +157 -0
  9. ClaudeSettings/hooks/README.md +254 -0
  10. ClaudeSettings/hooks/save_chat_plain.py +148 -0
  11. ClaudeSettings/hooks/save_chat_spec.py +398 -0
  12. ClaudeSettings/rules/README.md +270 -0
  13. ClaudeSettings/rules/go/.golangci.yml.template +170 -0
  14. ClaudeSettings/rules/go/GoBuildAutoVersion.v250425.md +95 -0
  15. ClaudeSettings/rules/go/check-standards.sh +128 -0
  16. ClaudeSettings/rules/go/coding-standards.md +973 -0
  17. ClaudeSettings/rules/go/example.go +207 -0
  18. ClaudeSettings/rules/go/go-testing.md +691 -0
  19. ClaudeSettings/rules/go/list-comments.sh +85 -0
  20. ClaudeSettings/settings.sample.json +71 -0
  21. ClaudeSettings/skills/README.md +225 -0
  22. ClaudeSettings/skills/zco-docs-update/SKILL.md +381 -0
  23. ClaudeSettings/skills/zco-help/SKILL.md +601 -0
  24. ClaudeSettings/skills/zco-plan/SKILL.md +661 -0
  25. ClaudeSettings/skills/zco-plan-new/SKILL.md +585 -0
  26. ClaudeSettings/zco-scripts/co-docs-update.sh +150 -0
  27. ClaudeSettings/zco-scripts/test_update_plan_metadata.py +328 -0
  28. ClaudeSettings/zco-scripts/update-plan-metadata.py +324 -0
  29. zco_claude-0.0.8.dist-info/METADATA +190 -0
  30. zco_claude-0.0.8.dist-info/RECORD +34 -0
  31. zco_claude-0.0.8.dist-info/WHEEL +5 -0
  32. zco_claude-0.0.8.dist-info/entry_points.txt +3 -0
  33. zco_claude-0.0.8.dist-info/top_level.txt +1 -0
  34. zco_claude_init.py +1732 -0
@@ -0,0 +1,691 @@
1
+ # Go 语言测试规则
2
+
3
+ ## Go 测试基础规范
4
+
5
+ ### 文件命名
6
+
7
+ **规则:测试文件必须以 `_test.go` 结尾。**
8
+
9
+ ```
10
+ user.go → user_test.go
11
+ validator.go → validator_test.go
12
+ service.go → service_test.go
13
+ ```
14
+
15
+ ### 测试函数签名
16
+
17
+ **规则:测试函数必须符合 Go 测试规范。**
18
+
19
+ ```go
20
+ // ✓ 正确
21
+ func TestRegisterUser(t *testing.T) {
22
+ // ...
23
+ }
24
+
25
+ func TestRegisterUser_ValidInput(t *testing.T) {
26
+ // ...
27
+ }
28
+
29
+ // ❌ 错误
30
+ func testRegisterUser(t *testing.T) { // 小写开头
31
+ // ...
32
+ }
33
+
34
+ func TestRegisterUser() { // 缺少 *testing.T 参数
35
+ // ...
36
+ }
37
+ ```
38
+
39
+ ### 包声明
40
+
41
+ **规则:测试文件可以使用相同包名或添加 `_test` 后缀。**
42
+
43
+ ```go
44
+ // 方式 1:黑盒测试(推荐用于测试公共 API)
45
+ package user_test
46
+
47
+ import (
48
+ "testing"
49
+ "myapp/internal/user"
50
+ )
51
+
52
+ func TestRegisterUser(t *testing.T) {
53
+ u, err := user.Register("test@example.com", "Pass123!")
54
+ // 只能访问公共 API
55
+ }
56
+
57
+ // 方式 2:白盒测试(用于测试内部逻辑)
58
+ package user
59
+
60
+ import "testing"
61
+
62
+ func TestValidateEmail(t *testing.T) {
63
+ err := validateEmail("test@example.com")
64
+ // 可以访问私有函数
65
+ }
66
+ ```
67
+
68
+ **选择建议:**
69
+ - 优先使用黑盒测试(`package xxx_test`)
70
+ - 只在必须测试私有函数时使用白盒测试
71
+ - 一个包可以同时有两种测试文件
72
+
73
+ ## Go 测试工具
74
+
75
+ ### 使用 testing 包
76
+
77
+ ```go
78
+ import "testing"
79
+
80
+ func TestExample(t *testing.T) {
81
+ // t.Error/t.Errorf - 报告错误但继续执行
82
+ if got != want {
83
+ t.Errorf("got %v, want %v", got, want)
84
+ }
85
+
86
+ // t.Fatal/t.Fatalf - 报告错误并停止测试
87
+ if err != nil {
88
+ t.Fatalf("unexpected error: %v", err)
89
+ }
90
+
91
+ // t.Log/t.Logf - 记录信息(只在失败或 -v 时显示)
92
+ t.Logf("Processing user: %s", user.Email)
93
+
94
+ // t.Skip/t.Skipf - 跳过测试
95
+ if runtime.GOOS == "windows" {
96
+ t.Skip("skipping test on Windows")
97
+ }
98
+ }
99
+ ```
100
+
101
+ ### 推荐使用 testify/assert
102
+
103
+ **安装:**
104
+ ```bash
105
+ go get github.com/stretchr/testify/assert
106
+ ```
107
+
108
+ **使用:**
109
+ ```go
110
+ import (
111
+ "testing"
112
+ "github.com/stretchr/testify/assert"
113
+ )
114
+
115
+ func TestRegisterUser(t *testing.T) {
116
+ user, err := RegisterUser("test@example.com", "Pass123!")
117
+
118
+ // 更清晰的断言
119
+ assert.NoError(t, err)
120
+ assert.NotNil(t, user)
121
+ assert.Equal(t, "test@example.com", user.Email)
122
+ assert.NotEmpty(t, user.ID)
123
+ assert.True(t, len(user.ID) > 0)
124
+ assert.Contains(t, user.Email, "@")
125
+ }
126
+ ```
127
+
128
+ ### 推荐使用 testify/mock(如果需要 mock)
129
+
130
+ ```go
131
+ import (
132
+ "github.com/stretchr/testify/mock"
133
+ )
134
+
135
+ type MockUserRepository struct {
136
+ mock.Mock
137
+ }
138
+
139
+ func (m *MockUserRepository) Save(user *User) error {
140
+ args := m.Called(user)
141
+ return args.Error(0)
142
+ }
143
+
144
+ func (m *MockUserRepository) FindByEmail(email string) (*User, error) {
145
+ args := m.Called(email)
146
+ if args.Get(0) == nil {
147
+ return nil, args.Error(1)
148
+ }
149
+ return args.Get(0).(*User), args.Error(1)
150
+ }
151
+
152
+ // 在测试中使用
153
+ func TestRegisterUser_EmailExists_ReturnsError(t *testing.T) {
154
+ mockRepo := new(MockUserRepository)
155
+ mockRepo.On("FindByEmail", "existing@example.com").
156
+ Return(&User{Email: "existing@example.com"}, nil)
157
+
158
+ service := NewUserService(mockRepo)
159
+ _, err := service.RegisterUser("existing@example.com", "Pass123!")
160
+
161
+ assert.Error(t, err)
162
+ mockRepo.AssertExpectations(t)
163
+ }
164
+ ```
165
+
166
+ ## 表驱动测试(Table-Driven Tests)
167
+
168
+ **Go 推荐的测试模式,适合测试多个相似场景。**
169
+
170
+ ### 基本结构
171
+
172
+ ```go
173
+ func TestValidateEmail(t *testing.T) {
174
+ tests := []struct {
175
+ name string // 测试名称
176
+ email string // 输入
177
+ wantErr bool // 期望是否有错误
178
+ }{
179
+ {
180
+ name: "有效邮箱",
181
+ email: "user@example.com",
182
+ wantErr: false,
183
+ },
184
+ {
185
+ name: "缺少@符号",
186
+ email: "userexample.com",
187
+ wantErr: true,
188
+ },
189
+ {
190
+ name: "空邮箱",
191
+ email: "",
192
+ wantErr: true,
193
+ },
194
+ }
195
+
196
+ for _, tt := range tests {
197
+ t.Run(tt.name, func(t *testing.T) {
198
+ err := ValidateEmail(tt.email)
199
+
200
+ if tt.wantErr {
201
+ assert.Error(t, err, "Expected error for %s", tt.name)
202
+ } else {
203
+ assert.NoError(t, err, "Unexpected error for %s", tt.name)
204
+ }
205
+ })
206
+ }
207
+ }
208
+ ```
209
+
210
+ ### 子测试(Subtests)
211
+
212
+ **使用 t.Run 创建子测试,提供更好的组织和错误报告。**
213
+
214
+ ```go
215
+ func TestUserService(t *testing.T) {
216
+ t.Run("注册用户", func(t *testing.T) {
217
+ t.Run("有效输入", func(t *testing.T) {
218
+ user, err := service.RegisterUser("user@example.com", "Pass123!")
219
+ assert.NoError(t, err)
220
+ assert.NotNil(t, user)
221
+ })
222
+
223
+ t.Run("无效邮箱", func(t *testing.T) {
224
+ _, err := service.RegisterUser("invalid", "Pass123!")
225
+ assert.Error(t, err)
226
+ })
227
+ })
228
+
229
+ t.Run("登录用户", func(t *testing.T) {
230
+ // ...
231
+ })
232
+ }
233
+ ```
234
+
235
+ **运行特定子测试:**
236
+ ```bash
237
+ go test -run TestUserService/注册用户/有效输入
238
+ ```
239
+
240
+ ## 测试辅助函数
241
+
242
+ ### Setup 和 Teardown
243
+
244
+ **使用辅助函数进行测试准备和清理。**
245
+
246
+ ```go
247
+ // 测试级别的 setup
248
+ func setupTest(t *testing.T) (*UserService, *MockRepository) {
249
+ mockRepo := new(MockRepository)
250
+ service := NewUserService(mockRepo)
251
+ return service, mockRepo
252
+ }
253
+
254
+ // 包级别的 setup/teardown
255
+ func TestMain(m *testing.M) {
256
+ // 全局 setup
257
+ setupDatabase()
258
+
259
+ // 运行测试
260
+ code := m.Run()
261
+
262
+ // 全局 teardown
263
+ teardownDatabase()
264
+
265
+ os.Exit(code)
266
+ }
267
+
268
+ // 使用 t.Cleanup(推荐)
269
+ func TestWithCleanup(t *testing.T) {
270
+ // 创建临时资源
271
+ tmpFile := createTempFile()
272
+
273
+ // 注册清理函数
274
+ t.Cleanup(func() {
275
+ os.Remove(tmpFile)
276
+ })
277
+
278
+ // 测试逻辑
279
+ // ...
280
+ }
281
+ ```
282
+
283
+ ### 测试辅助函数命名
284
+
285
+ **辅助函数应以 `test` 开头(小写),避免被识别为测试函数。**
286
+
287
+ ```go
288
+ // ✓ 正确:辅助函数
289
+ func testCreateUser(t *testing.T, email string) *User {
290
+ t.Helper() // 标记为辅助函数,错误时显示调用者的行号
291
+ user, err := CreateUser(email, "Pass123!")
292
+ if err != nil {
293
+ t.Fatalf("failed to create user: %v", err)
294
+ }
295
+ return user
296
+ }
297
+
298
+ // 在测试中使用
299
+ func TestUserOperations(t *testing.T) {
300
+ user := testCreateUser(t, "test@example.com")
301
+ // ...
302
+ }
303
+ ```
304
+
305
+ ## Go 特定的测试技巧
306
+
307
+ ### 1. 使用接口进行 Mock
308
+
309
+ **定义接口以便于测试时替换实现。**
310
+
311
+ ```go
312
+ // 定义接口
313
+ type UserRepository interface {
314
+ Save(user *User) error
315
+ FindByEmail(email string) (*User, error)
316
+ }
317
+
318
+ // 生产实现
319
+ type PostgresUserRepository struct {
320
+ db *sql.DB
321
+ }
322
+
323
+ func (r *PostgresUserRepository) Save(user *User) error {
324
+ // 真实数据库操作
325
+ }
326
+
327
+ // 测试实现
328
+ type InMemoryUserRepository struct {
329
+ users map[string]*User
330
+ }
331
+
332
+ func (r *InMemoryUserRepository) Save(user *User) error {
333
+ r.users[user.Email] = user
334
+ return nil
335
+ }
336
+
337
+ // 服务依赖接口,不依赖具体实现
338
+ type UserService struct {
339
+ repo UserRepository
340
+ }
341
+
342
+ func NewUserService(repo UserRepository) *UserService {
343
+ return &UserService{repo: repo}
344
+ }
345
+ ```
346
+
347
+ ### 2. 测试并发代码
348
+
349
+ **测试涉及 goroutine 的代码。**
350
+
351
+ ```go
352
+ func TestConcurrentAccess(t *testing.T) {
353
+ counter := NewSafeCounter()
354
+
355
+ // 使用 WaitGroup 等待所有 goroutine
356
+ var wg sync.WaitGroup
357
+ goroutines := 100
358
+ increments := 1000
359
+
360
+ for i := 0; i < goroutines; i++ {
361
+ wg.Add(1)
362
+ go func() {
363
+ defer wg.Done()
364
+ for j := 0; j < increments; j++ {
365
+ counter.Increment()
366
+ }
367
+ }()
368
+ }
369
+
370
+ wg.Wait()
371
+
372
+ expected := goroutines * increments
373
+ assert.Equal(t, expected, counter.Value())
374
+ }
375
+
376
+ // 检测竞态条件
377
+ // go test -race ./...
378
+ ```
379
+
380
+ ### 3. 测试 Panic
381
+
382
+ ```go
383
+ func TestDivide_ByZero_Panics(t *testing.T) {
384
+ assert.Panics(t, func() {
385
+ Divide(10, 0)
386
+ }, "Divide by zero should panic")
387
+ }
388
+
389
+ // 或者使用 recover
390
+ func TestDivide_ByZero_Panics_Manual(t *testing.T) {
391
+ defer func() {
392
+ if r := recover(); r == nil {
393
+ t.Error("Expected panic but didn't get one")
394
+ }
395
+ }()
396
+
397
+ Divide(10, 0)
398
+ }
399
+ ```
400
+
401
+ ### 4. 测试 HTTP Handler
402
+
403
+ ```go
404
+ import (
405
+ "net/http"
406
+ "net/http/httptest"
407
+ )
408
+
409
+ func TestUserHandler_Register(t *testing.T) {
410
+ // 创建请求
411
+ reqBody := `{"email":"user@example.com","password":"Pass123!"}`
412
+ req := httptest.NewRequest("POST", "/api/users/register",
413
+ strings.NewReader(reqBody))
414
+ req.Header.Set("Content-Type", "application/json")
415
+
416
+ // 创建响应记录器
417
+ rr := httptest.NewRecorder()
418
+
419
+ // 调用 handler
420
+ handler := NewUserHandler(mockService)
421
+ handler.ServeHTTP(rr, req)
422
+
423
+ // 断言
424
+ assert.Equal(t, http.StatusCreated, rr.Code)
425
+ assert.Contains(t, rr.Body.String(), "user@example.com")
426
+ }
427
+ ```
428
+
429
+ ### 5. 使用 Testdata 目录
430
+
431
+ **Go 约定:测试数据放在 `testdata` 目录中。**
432
+
433
+ ```
434
+ mypackage/
435
+ ├── user.go
436
+ ├── user_test.go
437
+ └── testdata/
438
+ ├── valid_user.json
439
+ ├── invalid_user.json
440
+ └── test_config.yaml
441
+ ```
442
+
443
+ ```go
444
+ func TestLoadUser(t *testing.T) {
445
+ data, err := os.ReadFile("testdata/valid_user.json")
446
+ assert.NoError(t, err)
447
+
448
+ var user User
449
+ err = json.Unmarshal(data, &user)
450
+ assert.NoError(t, err)
451
+ assert.Equal(t, "user@example.com", user.Email)
452
+ }
453
+ ```
454
+
455
+ ## 基准测试(Benchmarks)
456
+
457
+ **测试性能时使用基准测试。**
458
+
459
+ ```go
460
+ func BenchmarkValidateEmail(b *testing.B) {
461
+ email := "user@example.com"
462
+
463
+ b.ResetTimer() // 重置计时器,忽略 setup 时间
464
+
465
+ for i := 0; i < b.N; i++ {
466
+ ValidateEmail(email)
467
+ }
468
+ }
469
+
470
+ // 运行基准测试
471
+ // go test -bench=. -benchmem
472
+ ```
473
+
474
+ ## 示例测试(Examples)
475
+
476
+ **可作为文档的示例测试。**
477
+
478
+ ```go
479
+ func ExampleRegisterUser() {
480
+ user, err := RegisterUser("user@example.com", "SecurePass123!")
481
+ if err != nil {
482
+ fmt.Println("Error:", err)
483
+ return
484
+ }
485
+
486
+ fmt.Println("User created:", user.Email)
487
+ // Output:
488
+ // User created: user@example.com
489
+ }
490
+ ```
491
+
492
+ ## Go 测试命令
493
+
494
+ ### 基本命令
495
+
496
+ ```bash
497
+ # 运行所有测试
498
+ go test ./...
499
+
500
+ # 运行并显示详细输出
501
+ go test -v ./...
502
+
503
+ # 运行特定包的测试
504
+ go test ./internal/user
505
+
506
+ # 运行特定测试
507
+ go test -run TestRegisterUser
508
+
509
+ # 运行匹配正则的测试
510
+ go test -run "TestRegister.*"
511
+
512
+ # 运行子测试
513
+ go test -run TestUserService/注册用户
514
+ ```
515
+
516
+ ### 覆盖率
517
+
518
+ ```bash
519
+ # 显示覆盖率
520
+ go test -cover ./...
521
+
522
+ # 生成覆盖率报告
523
+ go test -coverprofile=coverage.out ./...
524
+
525
+ # 查看覆盖率详情
526
+ go tool cover -func=coverage.out
527
+
528
+ # 生成 HTML 报告
529
+ go tool cover -html=coverage.out
530
+ ```
531
+
532
+ ### 其他有用参数
533
+
534
+ ```bash
535
+ # 检测竞态条件
536
+ go test -race ./...
537
+
538
+ # 运行基准测试
539
+ go test -bench=. ./...
540
+
541
+ # 查看内存分配
542
+ go test -bench=. -benchmem ./...
543
+
544
+ # 设置超时
545
+ go test -timeout 30s ./...
546
+
547
+ # 并行运行测试
548
+ go test -parallel 4 ./...
549
+
550
+ # 短测试模式(跳过耗时测试)
551
+ go test -short ./...
552
+ ```
553
+
554
+ ## 测试组织最佳实践
555
+
556
+ ### 1. 文件组织
557
+
558
+ ```
559
+ mypackage/
560
+ ├── user.go # 实现代码
561
+ ├── user_test.go # 黑盒测试
562
+ ├── user_internal_test.go # 白盒测试(如果需要)
563
+ ├── mock_repository.go # Mock 对象
564
+ └── testdata/ # 测试数据
565
+ └── users.json
566
+ ```
567
+
568
+ ### 2. 测试分类
569
+
570
+ **使用 build tags 分类测试。**
571
+
572
+ ```go
573
+ // +build integration
574
+
575
+ package user_test
576
+
577
+ func TestDatabaseIntegration(t *testing.T) {
578
+ // 集成测试
579
+ }
580
+ ```
581
+
582
+ ```bash
583
+ # 只运行单元测试(默认)
584
+ go test ./...
585
+
586
+ # 运行集成测试
587
+ go test -tags=integration ./...
588
+ ```
589
+
590
+ ### 3. 测试命名层次
591
+
592
+ ```go
593
+ func TestUserService(t *testing.T) {
594
+ t.Run("Register", func(t *testing.T) {
595
+ t.Run("ValidInput", func(t *testing.T) {
596
+ t.Run("CreatesUser", func(t *testing.T) {
597
+ // ...
598
+ })
599
+ t.Run("ReturnsUserID", func(t *testing.T) {
600
+ // ...
601
+ })
602
+ })
603
+ t.Run("InvalidEmail", func(t *testing.T) {
604
+ // ...
605
+ })
606
+ })
607
+ }
608
+ ```
609
+
610
+ ## 常见陷阱
611
+
612
+ ### ❌ 陷阱 1:共享状态
613
+
614
+ ```go
615
+ // ❌ 错误:测试间共享状态
616
+ var testUser *User
617
+
618
+ func TestCreateUser(t *testing.T) {
619
+ testUser = CreateUser("test@example.com")
620
+ }
621
+
622
+ func TestUpdateUser(t *testing.T) {
623
+ UpdateUser(testUser, "new@example.com") // 依赖上一个测试
624
+ }
625
+
626
+ // ✓ 正确:每个测试独立
627
+ func TestUpdateUser(t *testing.T) {
628
+ user := CreateUser("test@example.com")
629
+ UpdateUser(user, "new@example.com")
630
+ }
631
+ ```
632
+
633
+ ### ❌ 陷阱 2:忽略错误
634
+
635
+ ```go
636
+ // ❌ 错误
637
+ func TestCreateUser(t *testing.T) {
638
+ user, _ := CreateUser("test@example.com") // 忽略错误
639
+ assert.NotNil(t, user)
640
+ }
641
+
642
+ // ✓ 正确
643
+ func TestCreateUser(t *testing.T) {
644
+ user, err := CreateUser("test@example.com")
645
+ assert.NoError(t, err)
646
+ assert.NotNil(t, user)
647
+ }
648
+ ```
649
+
650
+ ### ❌ 陷阱 3:不使用 t.Helper()
651
+
652
+ ```go
653
+ // ❌ 错误:辅助函数不标记 Helper
654
+ func createTestUser(t *testing.T) *User {
655
+ user, err := CreateUser("test@example.com")
656
+ if err != nil {
657
+ t.Fatal(err) // 错误会显示这一行,而不是调用者
658
+ }
659
+ return user
660
+ }
661
+
662
+ // ✓ 正确
663
+ func createTestUser(t *testing.T) *User {
664
+ t.Helper() // 标记为辅助函数
665
+ user, err := CreateUser("test@example.com")
666
+ if err != nil {
667
+ t.Fatal(err) // 错误会显示调用者的行号
668
+ }
669
+ return user
670
+ }
671
+ ```
672
+
673
+ ## 测试覆盖率目标
674
+
675
+ - **包级别**:≥ 80%
676
+ - **关键业务逻辑**:≥ 90%
677
+ - **公共 API**:100%
678
+ - **错误处理路径**:≥ 80%
679
+
680
+ ## 质量检查清单
681
+
682
+ - [ ] 所有测试文件以 `_test.go` 结尾
683
+ - [ ] 测试函数以 `Test` 开头
684
+ - [ ] 使用表驱动测试处理多个场景
685
+ - [ ] 使用 `t.Run` 组织子测试
686
+ - [ ] 辅助函数使用 `t.Helper()`
687
+ - [ ] 不忽略错误返回值
688
+ - [ ] 测试相互独立
689
+ - [ ] 运行 `go test -race` 无竞态条件
690
+ - [ ] 覆盖率达标
691
+ - [ ] 测试执行快速