在 Go 中,testing 包是标准库的一部分,用于编写和执行单元测试。它为编写、执行和组织测试提供了丰富的功能,包括断言、基准测试、示例测试等。
1. 单元测试
Go 的单元测试是基于函数和方法的,测试文件通常以 _test.go 结尾,测试函数以 Test 开头。
1.1. 编写单元测试
// calculator.go
package calculator
func Add(a, b int) int {
return a + b
}
// calculator_test.go
package calculator
import "testing"
// 测试 Add 函数
func TestAdd(t *testing.T) {
result := Add(1, 2)
expected := 3
if result != expected {
t.Errorf("Expected %d, but got %d", expected, result)
}
}- 测试函数名必须以
Test开头,且接受一个*testing.T类型的参数。 - 使用
t.Errorf或t.Fatal来报告错误。
1.2. 运行单元测试
你可以使用 go test 命令来运行测试。
go test- 这将会自动查找当前目录下的所有
_test.go文件并执行其中的测试函数。
1.3. 测试输出
Go 的测试框架提供了不同的报告方式。默认情况下,测试失败时,go test 会输出类似下面的信息:
--- FAIL: TestAdd (0.00s)
calculator_test.go:10: Expected 3, but got 4
FAIL
exit status 1
FAIL calculator 0.004s2. 基准测试
基准测试用于测试代码的性能。基准测试函数以 Benchmark 开头,并接受一个 *testing.B 类型的参数。
2.1. 编写基准测试
// benchmark_test.go
package calculator
import "testing"
// 基准测试 Add 函数
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(1, 2)
}
}- 基准测试的循环次数由
b.N决定。Go 的基准测试框架会自动调整b.N,以便获得准确的基准结果。 b.N是测试运行次数,Go 会根据运行时间自动调整。
2.2. 运行基准测试
使用 go test 命令并加上 -bench 标志来运行基准测试:
go test -bench .- 这将会执行所有基准测试,并输出性能结果,例如:
BenchmarkAdd-8 2000000 1200 ns/opns/op是每次操作的平均纳秒数。
3. 示例测试
Go 也支持示例测试(Example Testing)。示例测试通常用于验证代码示例是否正确。它们的测试函数以 Example 开头。
3.1. 编写示例测试
// calculator_test.go
package calculator
import "fmt"
// ExampleAdd 展示如何使用 Add 函数
func ExampleAdd() {
fmt.Println(Add(1, 2))
// 输出: 3
}ExampleAdd函数展示了Add函数的使用方法,且在测试过程中会检查其输出是否符合预期。
3.2. 运行示例测试
使用 go test 命令来运行示例测试:
go test -v-v标志会使测试输出更详细,包括示例测试的输出。
输出会类似于:
=== RUN ExampleAdd
--- PASS: ExampleAdd (0.00s)
calculator_test.go:10: 3
PASS
ok calculator 0.003s4. 并发测试
Go 的测试框架支持并发执行多个测试。在 Go 的测试中,你可以通过 t.Parallel() 来并行执行测试。
4.1. 并发执行测试
func TestAdd(t *testing.T) {
t.Parallel() // 并发执行此测试
result := Add(1, 2)
expected := 3
if result != expected {
t.Errorf("Expected %d, but got %d", expected, result)
}
}t.Parallel()会告诉 Go 在执行该测试时使用并发执行。这对于测试多个独立操作是非常有用的。
5. 测试覆盖率
Go 提供了覆盖率报告,可以查看代码的哪些部分被测试覆盖到了,哪些没有。你可以使用 -cover 标志来生成覆盖率报告。
5.1. 运行覆盖率报告
go test -cover- 输出将包括每个测试函数的覆盖率,例如:
PASS
coverage: 100.0% of statements
ok calculator 0.004s5.2. 生成 HTML 格式的覆盖率报告
如果你想查看更详细的覆盖率信息,可以生成 HTML 格式的报告:
go test -coverprofile=coverage.out
go tool cover -html=coverage.out -o coverage.htmlcoverage.out文件包含了测试覆盖率的数据。go tool cover -html=coverage.out -o coverage.html会生成一个 HTML 文件,你可以在浏览器中查看详细的覆盖率报告。
6. 测试配置和生命周期
6.1. testing.T 的常用方法
t.Log():记录测试日志,会在测试成功时显示。got.Log("This is a log message")t.Error():记录错误,但继续执行测试。got.Error("This is an error")t.Fatal():记录错误并立即停止当前测试。got.Fatal("This is a fatal error")t.FailNow():立即停止当前测试,但不报告错误。
6.2. setup 和 teardown
如果你需要在每个测试之前和之后执行一些代码,可以使用 setup 和 teardown 模式,通常通过 t.Cleanup() 或 defer 来实现。
func TestSomething(t *testing.T) {
t.Cleanup(func() {
// 清理代码,测试结束后调用
fmt.Println("Cleanup!")
})
// 测试逻辑
fmt.Println("Test logic here!")
}7. Mock 和断言
Go 标准库的 testing 包没有内建的 mocking 框架和断言库,但你可以使用第三方库,如 github.com/stretchr/testify,它提供了强大的断言功能和 mock 对象。
7.1. 使用 github.com/stretchr/testify
安装 testify 包:
go get github.com/stretchr/testify使用 testify 的断言功能:
package calculator
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestAdd(t *testing.T) {
result := Add(1, 2)
assert.Equal(t, 3, result, "Expected result should be 3")
}8. 总结
- 单元测试:使用
testing包编写并运行,测试函数需要以Test开头,接受*testing.T参数。 - 基准测试:通过
Benchmark开头的函数来测试性能,使用go test -bench运行。 - 示例测试:通过
Example开头的函数来展示如何使用某些函数。 - 并发测试:可以使用
t.Parallel()来并发执行测试。 - 测试覆盖率:可以通过
-cover标志来查看测试覆盖率,生成详细的报告。 - 清理操作:使用
t.Cleanup()和defer来处理测试的清理工作。 - 断言和 Mock:可以使用第三方库(如
testify)来进行更复杂的断言和 mocking。
testing 包为 Go 提供了全面的测试支持,使得编写和执行单元测试变得简洁高效,适用于单元测试、性能测试、示例测试等各种场景。