单元测试专注于隔离代码单元,而集成测试检查组件交互。在 go 中,单元测试使用 testing 框架和 testify/assert 库进行断言,集成测试使用 testing.t.run 和 mock 对象模拟依赖项。最佳实践包括原子测试、断言库、自动化和可维护的测试。
Go 框架中的单元测试和集成测试
在 Go 应用程序中进行测试对于确保代码的可靠性和正确性至关重要。本文将探讨单元测试和集成测试的最佳实践以及如何使用流行的 Go 测试框架如 testing 和 testify/assert 进行测试。
单元测试
立即学习“go语言免费学习笔记(深入)”;
单元测试专注于单个代码单元,例如函数或结构。它们隔离代码,避免外部依赖项的影响。
实战案例:
package calculator
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestAdd(t *testing.T) {
result := Add(5, 10)
assert.Equal(t, 15, result)
}
在本例中,我们使用 assert.Equal 断言 Add 函数的结果为 15。
集成测试
集成测试检查多个组件的交互,包括数据库、外部服务和用户界面。与单元测试不同,它们不模拟依赖项。
实战案例:
package user
import (
"testing"
"errors"
"github.com/stretchr/testify/assert"
)
type UserService struct {
Repo UserRepository
}
func (u *UserService) CreateUser(name string) (*User, error) {
return u.Repo.Create(name)
}
func TestUserService_CreateUser(t *testing.T) {
type args struct {
name string
}
tests := []struct {
name string
args args
want *User
err error
}{
{
name: "valid user",
args: args{
name: "John Doe",
},
want: &User{
Name: "John Doe",
},
},
{
name: "empty user",
args: args{
name: "",
},
err: errors.New("invalid name"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
repo := &UserRepositoryMock{}
if tt.err != nil {
repo.CreateFunc = func(name string) (*User, error) {
return nil, tt.err
}
}
service := &UserService{
Repo: repo,
}
got, err := service.CreateUser(tt.args.name)
assert.Equal(t, tt.want, got)
assert.Equal(t, tt.err, err)
})
}
}
本例使用 testing.T.Run 进行子测试,并使用 mock 对象模拟 UserRepository 的 Create 方法,让测试独立于外部数据库依赖。
最佳实践
- 编写原子测试:每个测试应检查单个行为。
- 使用断言库:testing 和 testify/assert 等库提供易于读取的断言。
- 自动化测试:使用 CI/CD 流水线或持续集成工具自动化测试。
- 编写可维护的测试:测试应易于理解和维护,并使用描述性名称。