单元测试
# golang 单元测试
本单元测试基于 golang gin 项目,使用 mysql、redis 数据库,权限控制使用 casbin
# 单元编写
# 简单示例
func genVersionNumber(version string) int {
var vn = 1
if strings.HasPrefix(version, "v") {
vs := strings.Split(version[1:], "-")
for _, v := range vs {
vn *= 1000
if n, err := strconv.Atoi(v); err != nil {
return 0
} else {
vn = vn + n
}
}
}
return vn
}
func Test_genVersionNumber(t *testing.T) {
type args struct {
version string
}
tests := []struct {
name string
args args
want int
}{
{"测试1", args{version: "v1-2-3"}, 1001002003},
{"测试2", args{version: "v1-12-3"}, 1001012003},
{"测试3", args{version: "v1-2-30"}, 1001002030},
{"测试4", args{version: "v1-21-3"}, 1001021003},
{"测试5", args{version: "v12-2-3"}, 1012002003},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, genVersionNumber(tt.args.version), "genVersionNumber(%v)", tt.args.version)
})
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# mock 使用
# mysql mock
Gorm 库:gorm.io/gorm v1.23.8 Gorm mock 库:github.com/DATA-DOG/go-sqlmock v1.5.0
- 启动 sql mock
func SetupMock() {
// mock sql.DB
sqlDB, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherRegexp))
if err != nil {
panic(err)
}
// open gorm db
gdb, err := gorm.Open(mysql.New(mysql.Config{Conn: sqlDB, SkipInitializeWithVersion: true}), &gorm.Config{
Logger: glog.ExportGormLogger(500 * time.Millisecond).LogMode(logger.Silent),
})
if err != nil {
panic(err)
}
mysqlDatabase = gdb
mysqlMock = mock
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- Query mock
db.SqlDBMock().ExpectQuery("^SELECT (.+) FROM `accounts` (.*)$").
WithArgs(1, 2, 12).
WillReturnRows(
sqlmock.NewRows([]string{"ID", "CreateAt", "studio_id"}).
AddRow(1, time.Now(), 1).
AddRow(2, time.Now(), 1),
)
1
2
3
4
5
6
7
2
3
4
5
6
7
- Transaction mock
db.SqlDBMock().ExpectBegin()
db.SqlDBMock().ExpectExec("^UPDATE `accounts` (.*)$").
WillReturnResult(sqlmock.NewResult(1, 1))
db.SqlDBMock().ExpectCommit()
1
2
3
4
2
3
4
# Redis mock
使用 redis 库 github.com/redis/go-redis/v9 使用 redis mock 库 github.com/go-redis/redismock/v9
rdb, mock = redismock.NewClientMock()
1
func TestCheckRedisBiDate(t *testing.T) {
ctx := context.Background()
mm := db.SetupMockRedis()
date := "2023-03-01"
redisKey := fmt.Sprintf(RedisBIDate, date)
mm.ExpectGet(redisKey).SetErr(errors.New("mock error"))
ok := CheckRedisBiDate(ctx, date)
assert.False(t, false, ok)
mm.ExpectGet(redisKey).SetVal("0")
ok = CheckRedisBiDate(ctx, date)
assert.False(t, false, ok)
mm.ExpectGet(redisKey).SetVal("1")
ok = CheckRedisBiDate(ctx, date)
assert.False(t, false, ok)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Casbin mock
使用 casbin 库:github.com/casbin/casbin/v2 v2.60.0 使用 casbin sql adapter:github.com/casbin/gorm-adapter/v3 v3.7.4 使用 casbin mock adapter:github.com/ShuaiGao/string-adapter v0.1.1
- 启动 casbin mock
func SetupMock() {
// casbin mock,只需要定制一个 adapter
a := sa.NewAdapter(&policy)
setup("", a)
}
1
2
3
4
5
2
3
4
5
- 添加权限
var userSub = permission.GetUserSub("zijia")
var resourceGroupSub = permission.GetGroupResourceSub("zijia")
_, _ = permission.Enforcer().AddRoleForUser(userSub, resourceGroupSub)
_, _ = permission.Enforcer().AddPolicy(resourceGroupSub, string(permission.CasbinStudio), "12")
1
2
3
4
5
2
3
4
5
# Func mock
Gomonkey 库:github.com/agiledragon/gomonkey/v2 v2.9.0
patch := gomonkey.ApplyFunc(Add, func(a, b int) {
return a+b
})
defer patch.Reset()
1
2
3
4
2
3
4
# Goroutine mock
Gomonkey 库:github.com/agiledragon/gomonkey/v2 v2.9.0 方法替换的实现原理:替换对应方法的指针
ctx := &gin.Context{Request: &http.Request{}}
ctx.Set(utils.USER_SUB, userSub)
timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
ctx.Request.WithContext(timeoutCtx)
goMonkeyCounter := 0
blockChannel := make(chan bool)
patches := gomonkey.ApplyFunc(UpdateReportPlatform, func(_ context.Context, _ ...*model.Account) {
goMonkeyCounter++
blockChannel <- true
})
defer func() {
select {
case <-timeoutCtx.Done():
break
case <-blockChannel:
break
}
patches.Reset()
assert.Equal(t, 1, goMonkeyCounter)
}()
_, code = PostAdvertisersBatch(ctx, in)
assert.Equal(t, 0, code)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 基准测试
参考其博客链接 https://blog.csdn.net/qq_39787367/article/details/113989485
# 测试报告
# 查看覆盖率
$ go test -cover
# 加入-coverprofile 参数,将覆盖率输出到文件
$ go test -cover -coverprofile=c.out ./...
# 查看输出文件
$ go tool cover -html=c.out
1
2
3
4
5
6
2
3
4
5
6
编辑 (opens new window)
上次更新: 2023/03/21, 12:47:55