08.错误处理与单元测试
错误处理与单元测试是软件开发过程中保证代码质量的关键步骤。
错误处理
Go
语言对错误处理有一个独特的方法。
它没有像 Java
或 Python
中那样的异常机制,而是将错误作为返回值。
这强制程序员显式地处理错误,而不是依赖于异常和捕获机制。
例子:
package main
import (
"errors"
"fmt"
)
// 模拟一个可能出错的函数
func divide(dividend, divisor float64) (float64, error) {
if divisor == 0 {
return 0, errors.New("cannot divide by zero")
}
return dividend / divisor, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Result:", result)
}
输出:
在这个例子中,divide
函数尝试除以 0
,这将导致一个错误。
函数返回一个错误值,调用者检查这个值并相应地处理它。
单元测试
在 Go
语言中,单元测试是通过内置的 testing
包和 go test
命令来实现的。🦌🔍
单元测试允许你验证各个部分(单元)的代码是否按照预期工作。
在 Go
中,一个单元通常是一个函数。
为了编写一个测试,你需要创建一个以 _test.go
结尾的文件。
让我们来看一个简单的例子,你有一个函数 Add
,它将两个整数相加,并返回结果。
编写一个 add.go
文件如下:
// add.go
package math
// Add 返回两个整数的和
func Add(x, y int) int {
return x + y
}
为了测试这个 Add
函数,你会创建一个名为 add_test.go
的文件。
编写一个 add_test.go
如下:
// add_test.go
package math
import "testing"
// TestAdd 测试 math.Add 函数
func TestAdd(t *testing.T) {
result := Add(1, 2)
expected := 3
if result != expected {
t.Errorf("Add(1, 2) = %d; 期望的结果是 %d", result, expected)
}
}
在测试文件中,你定义了一个测试函数 TestAdd
。
它使用 testing.T
参数,该参数提供了方法用于报告和记录测试失败。
两个文件放到同一个目录,进入该目录下。
通过运行 go test
命令,Go
会自动找到所有的测试文件和测试函数,并执行它们。
go test
输出:
修改 expected := 3
为 expected := 4
// add_test.go
package math
import "testing"
// TestAdd 测试 math.Add 函数
func TestAdd(t *testing.T) {
result := Add(1, 2)
expected := 3
if result != expected {
t.Errorf("Add(1, 2) = %d; 期望的结果是 %d", result, expected)
}
}
再次测试,输出为:
如果测试通过了,你通常不会看到任何输出。
如果测试失败了,go test
会打印出失败的测试和相应的错误信息。
表格驱动测试
表格驱动测试是一种组织单元测试的方法,它允许你使用相同的测试逻辑来测试不同的输入。
func TestAddTableDriven(t *testing.T) {
var tests = []struct {
x int
y int
expected int
}{
{1, 2, 3},
{1, 1, 2},
{2, 2, 4},
}
for _, tt := range tests {
testname := fmt.Sprintf("%d+%d", tt.x, tt.y)
t.Run(testname, func(t *testing.T) {
ans := Add(tt.x, tt.y)
if ans != tt.expected {
t.Errorf("got %d, want %d", ans, tt.expected)
}
})
}
}
在这个例子中,我们定义了一个测试用例的切片。
每个测试用例包含输入 x
和 y
以及预期的结果 expected
。
t.Run
允许我们为每个测试用例运行一个子测试。
单元测试是提高你的代码可靠性的重要工具。
通过持续测试你的代码,你可以确保新的变更不会破坏现有的功能,并且可以快速发现和修复错误。