
在Go语言开发中,对数据库操作进行单元测试时,通常不希望连接真实数据库。为了保证测试的快速性和可重复性,推荐使用接口抽象和模拟(mock)技术来替代实际的数据库调用。下面是一个使用Golang接口 + 模拟实现进行数据库操作单元测试的完整示例。
假设我们有一个用户服务,需要查询和保存用户信息。先定义User结构体和数据库接口:
type User struct {
ID int
Name string
}
type UserDB interface {
GetUser(id int) (*User, error)
SaveUser(user *User) error
}
UserService依赖UserDB接口,而不是具体实现,便于注入模拟对象:
type UserService struct {
db UserDB
}
func NewUserService(db UserDB) *UserService {
return &UserService{db: db}
}
func (s *UserService) GetUserName(id int) (string, error) {
user, err := s.db.GetUser(id)
if err != nil {
return "", err
}
if user == nil {
return "", fmt.Errorf("user not found")
}
return user.Name, nil
}
func (s *UserService) RenameUser(id int, name string) error {
user, err := s.db.GetUser(id)
if err != nil {
return err
}
if user == nil {
return fmt.Errorf("user not found")
}
user.Name = name
return s.db.SaveUser(user)
}
在测试包中创建一个模拟的UserDB实现,控制返回值以覆盖各种场景:
立即学习“go语言免费学习笔记(深入)”;
type MockUserDB struct {
users map[int]*User
}
func NewMockUserDB() *MockUserDB {
return &MockUserDB{
users: make(map[int]*User),
}
}
func (m *MockUserDB) GetUser(id int) (*User, error) {
if user, exists := m.users[id]; exists {
return user, nil
}
return nil, nil // 不返回错误,仅返回nil表示未找到
}
func (m *MockUserDB) SaveUser(user *User) error {
m.users[user.ID] = user
return nil
}
使用模拟数据库测试业务逻辑,无需启动真实数据库:
func TestUserService_GetUserName(t *testing.T) {
mockDB := NewMockUserDB()
mockDB.users[1] = &User{ID: 1, Name: "Alice"}
service := NewUserService(mockDB)
name, err := service.GetUserName(1)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if name != "Alice" {
t.Errorf("expected name Alice, got %s", name)
}
}
func TestUserService_RenameUser(t *testing.T) {
mockDB := NewMockUserDB()
mockDB.users[2] = &User{ID: 2, Name: "Bob"}
service := NewUserService(mockDB)
err := service.RenameUser(2, "Bobby")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
updatedUser, _ := mockDB.GetUser(2)
if updatedUser.Name != "Bobby" {
t.Errorf("expected name Bobby, got %s", updatedUser.Name)
}
}
func TestUserService_RenameUser_NotFound(t *testing.T) {
mockDB := NewMockUserDB()
service := NewUserService(mockDB)
err := service.RenameUser(999, "Charlie")
if err == nil {
t.Fatal("expected error when user not found, got nil")
}
}
基本上就这些。通过接口抽象+模拟实现,可以完全隔离数据库依赖,写出高效、可靠的单元测试。这种方式简单直接,不需要引入外部库如sqlmock或testify,适合中小型项目或学习理解mock原理。
以上就是Golang模拟数据库操作进行单元测试示例的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号