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

posted on 2021-10-09 21:49  飞飞乐园  阅读(1603)  评论(0编辑  收藏  举报