测试是确保代码质量和可靠性的关键部分。Testify 是一个流行的测试工具集,它提供了一系列简化测试编写和执行的功能。本文将详细介绍如何使用 Testify 库进行单元测试。
安装
go get -u github.com/stretchr/testify
基础测试
创建一个测试文件,例如 test/my_test.go,并编写测试函数
package test
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Add(a, b int) int {
return a + b
}
func TestAdd(t *testing.T) {
result := Add(2, 3)
assert.Equal(t, 5, result, "2 + 3 应该等于 5")
}
运行
cd test
go test
断言函数
- assert.Equal(t, expected, actual):断言两个值相等。
- assert.NotEqual(t, expected, actual):断言两个值不相等。
- assert.Nil(t, obj):断言对象为 nil。
- assert.NotNil(t, obj):断言对象不为 nil。
- assert.True(t, condition):断言条件为 true。
- assert.False(t, condition):断言条件为 false。
- assert.Contains(t, haystack, needle):断言字符串或 slice 中包含某个元素。
表格驱动子测试
func TestAdd2(t *testing.T) {
tests := []struct {
name string
inputA int
inputB int
expected int
}{
{"Add positive numbers", 2, 3, 5},
{"Add negative numbers", -2, -3, -5},
{"Add zero", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.inputA, tt.inputB)
assert.Equal(t, tt.expected, result, "结果不符合期望")
})
}
}
使用 require
require 和 assert 类似,但区别在于:require 会在断言失败时直接终止测试,而 assert 会继续执行测试。
package main
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestDivision(t *testing.T) {
num := 10
denom := 0
// 如果断言失败,测试将直接终止
require.NotEqual(t, denom, 0, "Denominator should not be zero")
result := num / denom
require.Equal(t, 0, result)
}
使用 Mock
Testify 提供了简单的 mock 库,可以模拟依赖关系中的方法或接口,帮助测试代码中的外部依赖(如数据库、API 调用等)。
package main
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// 定义一个接口
type MyService interface {
GetData(id int) string
}
// 定义一个 Mock 结构体,继承 testify 的 mock.Mock
type MockService struct {
mock.Mock
}
// 实现 MyService 接口的方法
func (m *MockService) GetData(id int) string {
args := m.Called(id)
return args.String(0)
}
func TestMyService(t *testing.T) {
// 创建 Mock 对象
mockService := new(MockService)
// 设置期望值
mockService.On("GetData", 1).Return("Mocked Data")
// 调用方法
result := mockService.GetData(1)
// 验证返回值
assert.Equal(t, "Mocked Data", result)
// 验证预期的调用是否发生
mockService.AssertExpectations(t)
}
测试套件 (Test Suites)
Testify 还提供了 suite 模块,允许将多个相关的测试组织成一个测试套件,并提供了 Setup 和 Teardown 方法,用于在测试之前或之后执行一些通用的初始化或清理工作。
package main
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
// 定义一个测试套件
type MyTestSuite struct {
suite.Suite
value int
}
// 初始化测试套件
func (suite *MyTestSuite) SetupTest() {
suite.value = 10
}
// 编写测试
func (suite *MyTestSuite) TestAddition() {
result := suite.value + 5
assert.Equal(suite.T(), 15, result)
}
// 清理工作
func (suite *MyTestSuite) TearDownTest() {
suite.value = 0
}
// 运行测试套件
func TestMyTestSuite(t *testing.T) {
suite.Run(t, new(MyTestSuite))
}
Setup 和 Teardown
有时候,你可能需要在测试开始之前进行一些设置或在测试结束后进行一些清理。Testify 提供了 Setup 和 Teardown 函数来满足这个需求。
func TestMain(m *testing.M) {
// 在测试开始之前进行设置
setup()
// 运行测试
code := m.Run()
// 在测试结束后进行清理
teardown()
// 返回测试结果
os.Exit(code)
}