sqlmock 是一个实现 sql/driver 的mock库。它不需要建立真正的数据库连接就可以在测试中模拟任何 sql 驱动程序的行为。使用它可以很方便的在编写单元测试的时候mock sql语句的执行结果。
安装mockgen
go get github.com/DATA-DOG/go-sqlmock
针对测试的数据库操作函数编写单元测试(本例为向数据库表插入数据)
数据库操作函数employees.go
func (repo *EmployeesRepository) CreateEmployee(employee *domain.Employees) (err error) {
err = repo.db.Debug().Create(&employee).Error
if err != nil {
err = fmt.Errorf("[repository.r.CreateEmployee] failed: employee = %+v, error = %w ", employee, err)
return
}
return
}
domain.Employees 数据结构
package domain
import(
"time"
)
type Employees struct{
ID int `json:"id" gorm:"primary_key"`
Code string `json:"code"`
Name string `json:"name"`
DepartmentID int `json:"departmentid"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
针对测试的数据库操作函数编写单元测试employees_test.go
package impl
import (
"testing"
"github.com/DATA-DOG/go-sqlmock"
"github.com/magiconair/properties/assert"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"server/domain"
)
func getDBMock() (*gorm.DB, sqlmock.Sqlmock, error) {
// mock一个*sql.DB对象,不需要连接真实的数据库
db, mock, err := sqlmock.New()
if err != nil {
return nil, nil, err
}
//测试时不需要真正连接数据库
gdb, err := gorm.Open(postgres.New(postgres.Config{
DriverName: "postgres",
PreferSimpleProtocol: true,
Conn: db,
}), &gorm.Config{})
if err != nil {
return nil, nil, err
}
return gdb, mock, nil
}
func TestEmployeesRepository_CreateEmployees(t *testing.T) {
type fields struct {
db *gorm.DB
}
type args struct {
employees *domain.Employees
}
db, mock, err := getDBMock()
assert.Equal(t, err, nil)
tests := []struct {
name string
fields fields
args args
invoke func(args)
wantErr bool
}{
{
name: "create Employees successful",
fields: fields{
db: db,
},
args: args{employees: &domain.Employees{
ID:0,
Code: "1",
Name:"zhangsan",
DepartmentID:1,
}},
invoke: func(args args) {
mock.ExpectQuery("INSERT INTO (.+)").WithArgs(
args.employees.Code, args.employees.Name,args.employees.DepartmentID,sqlmock.AnyArg(),sqlmock.AnyArg(),sqlmock.AnyArg()).
WillReturnRows(sqlmock.NewRows([]string{"ID"}).AddRow(1))
},
},
{
name: "create Employees failed",
fields: fields{
db: db,
},
args: args{employees: &domain.Employees{
Code: "1",
Name:"zhangsan",
DepartmentID:2,
}},
invoke: func(args args) {
mock.ExpectQuery("INSERT INTO (.+)").WithArgs(
args.employees.Code,args.employees.Name,args.employees.DepartmentID,sqlmock.AnyArg(),sqlmock.AnyArg(),sqlmock.AnyArg()).
WillReturnError(gorm.ErrInvalidData)
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &EmployeesRepository{
db: tt.fields.db,
}
tt.invoke(tt.args)
if err := c.CreateEmployee(tt.args.employees); (err != nil) != tt.wantErr {
t.Errorf("CreateEmployees() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
在测试文件所在目录下,执行go test -v
执行结果
21:46:24.176',NULL) RETURNING "id"
--- PASS: TestEmployeesRepository_CreateEmployees (0.00s)
--- PASS: TestEmployeesRepository_CreateEmployees/create_Employees_successful (0.00s)
--- PASS: TestEmployeesRepository_CreateEmployees/create_Employees_failed (0.00s)
PASS
ok server/repository/impl 0.008s
所有博客均为自己学习的笔记。如有错误敬请理解。