一,安装需要用到的库
1,gorm官网:
2,安装gorm
liuhongdi@ku:~$ go get -u gorm.io/gorm
3,go-sqlmock的地址:
4,从命令行安装go-sqlmock:
liuhongdi@ku:~$ go get -u github.com/DATA-DOG/go-sqlmock
说明:刘宏缔的go森林是一个专注golang的博客,
网站:https://blog.imgtouch.com
原文: go语言单元测试之五:go语言用go-sqlmock和gorm做数据库查询mock – 架构森林
二,演示项目的相关信息
2,功能说明:演示了单元测试时用sqlmock摸拟数据库的数据记录
3,项目结构:如图:
三,go代码说明
1,global/db.go
package global
import (
"gorm.io/gorm"
"time"
"gorm.io/driver/mysql"
)
var (
DBLink *gorm.DB
)
//创建mysql链接
func SetupDBLink() (error) {
var err error
dsn:="root:password@tcp(127.0.0.1:3306)/business?charset=utf8&parseTime=True&loc=Local";
DBLink, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
//DBLink.Logger.LogMode(true)
if err != nil {
return err
}
sqlDB, err := DBLink.DB()
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns 设置打开数据库连接的最大数量
sqlDB.SetMaxOpenConns(30)
// SetConnMaxLifetime 设置了连接可复用的最大时间
sqlDB.SetConnMaxLifetime(time.Hour)
return nil
}
2,controller/userController.go
package controller
import (
"github.com/liuhongdi/unittest04/global"
"github.com/liuhongdi/unittest04/model"
)
func GoodsOne(goodsId int) (*model.Goods, error) {
goodsOne:=&model.Goods{}
err := global.DBLink.Where("goodsId=?",goodsId).First(&goodsOne).Error
//fmt.Println(err)
if (err != nil) {
return nil,err
} else {
return goodsOne,nil
}
}
3,model/goods.go
package model
type Goods struct {
GoodsId int64 `gorm:"column:goodsId",json:"goodsid"` // 自增
GoodsName string `gorm:"column:goodsName",json:"goodsname"` //
Subject string `gorm:"column:subject",json:"subject"`
Price string `gorm:"column:price",json:"price"`
Stock int `gorm:"column:stock",json:"stock"`
}
func (Goods) TableName() string {
return "goods"
}
4,main.go
package main
import (
"fmt"
"github.com/liuhongdi/unittest04/controller"
"github.com/liuhongdi/unittest04/global"
"log"
)
//定义一个加法方法
func add(a, b int) int {
return a + b
}
func init() {
//mysql link
err := global.SetupDBLink()
if err != nil {
log.Fatalf("init.setupDBEngine err: %v", err)
}
}
func main() {
goods,err := controller.GoodsOne(1)
if (err != nil){
log.Fatalf("err:%v",err)
} else {
fmt.Println(goods)
}
}
5,main_test.go
package main
import (
"database/sql"
"errors"
"fmt"
"github.com/DATA-DOG/go-sqlmock"
"github.com/liuhongdi/unittest04/controller"
"github.com/liuhongdi/unittest04/global"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
"testing"
)
var mock sqlmock.Sqlmock
//初始化
func init() {
//创建sqlmock
var err error
var db *sql.DB
db, mock, err = sqlmock.New()
if nil != err {
log.Fatalf("Init sqlmock failed, err %v", err)
}
//结合gorm、sqlmock
global.DBLink, err = gorm.Open(mysql.New(mysql.Config{
SkipInitializeWithVersion: true,
Conn: db,
}), &gorm.Config{})
if nil != err {
log.Fatalf("Init DB with sqlmock failed, err %v", err)
}
}
//测试得到一件商品的信息,启用sqlmock,放回结果集
func TestOneMockRes(t *testing.T) {
goodsId:=1
//创建数据库记录
rows := sqlmock.NewRows([]string{"goodsId", "goodsName", "subject", "price", "stock"}).
AddRow(2, "Moonii陶瓷月相灯", "这是一件测试商品", "5.32", "33")
mock.ExpectQuery("^SELECT \\* FROM `goods` WHERE goodsId=\\? ORDER BY `goods`.`goodsId` LIMIT 1").
WithArgs(goodsId).WillReturnRows(rows)
//执行
goods,err:=controller.GoodsOne(goodsId)
if (err != nil) {
t.Fatalf("goodsId: %d, err:%v", goodsId, err)
}else {
fmt.Println(goods)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("there were unfulfilled expectations: %s", err)
}
}
//测试得到一件商品的信息,启用sqlmock,无结果集
func TestOneMockNoRes(t *testing.T) {
goodsId:=1
//创建数据库记录
rows := sqlmock.NewRows([]string{"goodsId", "goodsName", "subject", "price", "stock"})
//AddRow(2, "Moonii陶瓷月相灯", "这是一件测试商品", "5.32", "33")
mock.ExpectQuery("^SELECT \\* FROM `goods` WHERE goodsId=\\? ORDER BY `goods`.`goodsId` LIMIT 1").
WithArgs(goodsId).WillReturnRows(rows)
//执行
goods,err:=controller.GoodsOne(goodsId)
if (err != nil) {
t.Fatalf("goodsId: %d, err:%v", goodsId, err)
}else {
fmt.Println(goods)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("there were unfulfilled expectations: %s", err)
}
}
//测试得到一件商品的信息,启用sqlmock,返回数据库错误
func TestOneMockError(t *testing.T) {
goodsId:=1
//传递sql
mock.ExpectQuery("^SELECT \\* FROM `goods` WHERE goodsId=\\? ORDER BY `goods`.`goodsId` LIMIT 1").
WithArgs(goodsId).WillReturnError(errors.New("some error"))
//执行
goods,err:=controller.GoodsOne(goodsId)
if (err != nil) {
t.Fatalf("goodsId: %d, err:%v", goodsId, err)
}else {
fmt.Println(goods)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("there were unfulfilled expectations: %s", err)
}
}
四,测试效果
执行测试命令:
root@ku:/data/go/unittest04# go test -v
返回:
root@ku:/data/go/unittest04# go test -v
=== RUN TestOneMockRes
&{2 Moonii陶瓷月相灯 这是一件测试商品 5.32 33}
--- PASS: TestOneMockRes (0.00s)
=== RUN TestOneMockNoRes
2021/02/01 10:20:56 /data/go/unittest04/controller/userController.go:10 record not found
[0.075ms] [rows:0] SELECT * FROM `goods` WHERE goodsId=1 ORDER BY `goods`.`goodsId` LIMIT 1
main_test.go:69: goodsId: 1, err:record not found
--- FAIL: TestOneMockNoRes (0.00s)
=== RUN TestOneMockError
2021/02/01 10:20:56 /data/go/unittest04/controller/userController.go:10 some error
[0.038ms] [rows:0] SELECT * FROM `goods` WHERE goodsId=1 ORDER BY `goods`.`goodsId` LIMIT 1
main_test.go:87: goodsId: 1, err:some error
--- FAIL: TestOneMockError (0.00s)
FAIL
exit status 1
FAIL github.com/liuhongdi/unittest04 0.012s
五,查看库的版本:
module github.com/liuhongdi/unittest04
go 1.15
require (
gorm.io/driver/mysql v1.0.1
gorm.io/gorm v1.20.6
github.com/DATA-DOG/go-sqlmock v1.5.0
)