package main import "testing" // 1. 最基础测试:准备输入 -> 调用函数 -> 比较实际值与期望值。 // 测试函数以 Test 开头,接收 *testing.T,没有返回值。 func TestAdd(t *testing.T) { got := add(2, 3) // got:实际得到的结果,是普通变量名。 want := 5 // want:期望结果,同样不是关键字。 if got != want { // Fatalf:记录失败信息、标记失败,并停止当前测试。 t.Fatalf("add(2, 3):实际=%d,期望=%d", got, want) } // Logf 只记录日志,不会把测试标记为失败;通过时用 -v 查看日志。 t.Logf("检查通过:实际=%d,期望=%d", got, want) } // 2. 表驱动测试:把多组输入和期望结果放到结构体切片里。 func TestAddTable(t *testing.T) { tests := []struct { name string a int b int want int }{ {name: "positive", a: 2, b: 3, want: 5}, {name: "zero", a: 0, b: 0, want: 0}, {name: "negative", a: -2, b: -3, want: -5}, {name: "mixed", a: -2, b: 3, want: 1}, } for _, tt := range tests { // Run 的参数:子测试名称、执行子测试的函数值。 // 匿名函数没有末尾的 (),由测试框架负责调用。 t.Run(tt.name, func(t *testing.T) { got := add(tt.a, tt.b) if got != tt.want { // Errorf:记录并标记失败,但继续执行当前测试后面的代码。 t.Errorf("add(%d, %d):实际=%d,期望=%d", tt.a, tt.b, got, tt.want) } }) } } // 3. 测试有 error 返回值的函数:成功路径和失败路径都要覆盖。 func TestParseScore(t *testing.T) { tests := []struct { name string input string want int wantErr bool }{ {name: "normal", input: "85", want: 85, wantErr: false}, {name: "lower_bound", input: "0", want: 0, wantErr: false}, {name: "upper_bound", input: "100", want: 100, wantErr: false}, {name: "below_range", input: "-1", wantErr: true}, {name: "above_range", input: "101", wantErr: true}, {name: "invalid_text", input: "abc", wantErr: true}, {name: "empty", input: "", wantErr: true}, {name: "decimal", input: "80.5", wantErr: true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := parseScore(tt.input) hasErr := err != nil if hasErr != tt.wantErr { t.Fatalf("parseScore(%q):错误=%v,期望发生错误=%t", tt.input, err, tt.wantErr) } if tt.wantErr { return // 已确认发生预期错误,本用例不再检查无效结果。 } if got != tt.want { t.Errorf("parseScore(%q):实际=%d,期望=%d", tt.input, got, tt.want) } }) } }