如何使用go优雅地撰写单元测试


本文摘自php中文网,作者藏色散人,侵删。

下面由golang教程栏目给大家介绍怎么使用go优雅地撰写单元测试,希望对需要的朋友有所帮助!

背景

刚刚加入一个年轻的小组,代码中的单元测试还没有来得及写,leader希望我通过单元测试来熟悉项目的业务逻辑。但是,代码量实在有点多,高效的完成单元测试成为首要目标。

实现原理

单元测试测用的是testify的测试框架,使用起来非常方便,具体的基础使用方法可以参考中文testify博客以及官方文档。

项目中的应用

初始化单元测试

在一个复杂的Web项目中,测试某一模块的功能往往需要先对这一模块所使用到的服务进行初始化,我们将初始化函数以及初始化函数所使用到的参数都放在同一个单元测试包下,例如对MySQL的初始化如下:

1

2

3

4

5

6

7

package unitTestfunc InitMySQL() error{

    return db.Init(constant.MySQLDSN,

    constant.MaxIdleConns,

    constant.MaxOpenConns,

    time.Duration(constant.ConnMaxLifetime)*time.Second,

    constant.EnableSqlLog)//其他包中已经封装了初始化函数,在测试包的初始化函数中调用即可}func CloseDB() error{

    return db.Close()}

我们在另一个contant包下存放对应的参数:

1

2

3

4

5

6

7

8

9

package constantconstant(

    MySQLDSN = "username:password@addresss/db?timeout=5000ms&readTimeout=5s&charset=utf8mb4"

    MaxIdleConns = 20

    MaxOpenConns = 20

    ConnMaxLifetime = 60

    EnableSqlLog = true

    MerchantID = 6666

    SheetID = "SZSWIMTEST"

    Operator = "XXXX@XXXX")

进行单元测试

以下以对数据库的操作为例
单元测试主要由三部分组成:
第一部分为固定写法

1

2

type ActionLogRepo struct {

    basetest.BaseSuite}

第二部分为对Register进行初始化,Register函数可以传入四个参数fun1,fun2,fun3,fun4
fun1:在该测试文件中的最开始执行一次。
fun2:在每个单元测试前都执行一次。
fun3:在每个单元测试后都执行一次。
fun4:在该测试文件中的最终执行一次。
根据需求,我们需要在所有单元测试开始前执行一次初始化数据库操作,以及在最后关闭数据库。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

func TestActionLogRepo(t *testing.T) {

    AgentSuite := new(ActionLogRepo)

    var err error

    AgentSuite.Register(

        func() {

            err = unitTest.InitMySQL()

        },

        nil,

        nil,

        func() {

            err = unitTest.CloseDB()

        })

    assert.Nil(t,err)

    suite.Run(t, AgentSuite)}

第三部分,进行单元测试,我们先在数据库中建立对应的数据,然后调用需要单元测试的函数进行对该数据的操作,之后使用assert对该结果进行验证,最后要记得删除掉单元测试的记录。

1

2

3

4

5

6

7

8

9

10

11

func (suite *ActionLogRepo) TestActionLog() {

    repo := repository.NewRepository()//获取数据库

    actionLog := &model.ActionLogTab{XXXXXX}

    err := CreateActionLog(actionLog)//创建测试的数据记录

    assert.Nil(suite.T(),err)

    logs,count,err := FetchActionLogs(repo,repo.MerchantID,actionLog.SheetID,actionLog.SheetType,1,1)//需要测试的函数

    assert.Nil(suite.T(),err)

    assert.Equal(suite.T(),logs[0].OperationTime,actionLog.OperationTime)//验证函数的正确性

 

    err = repo.MerchantDB().Delete(actionLog).Error//删除掉测试的数据库记录

    assert.Nil(suite.T(),err)}

最终的测试文件结构如下:

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

package testtype ActionLogRepo struct {

    basetest.BaseSuite}func TestActionLogRepo(t *testing.T) {

    AgentSuite := new(ActionLogRepo)

    var err error

    AgentSuite.Register(

        func() {

            err = unitTest.InitMySQL()

        },

        nil,

        nil,

        func() {

            err = unitTest.CloseDB()

        })

    assert.Nil(t,err)

    suite.Run(t, AgentSuite)}func (suite *ActionLogRepo) TestActionLog() {

    repo := repository.NewRepository()//获取数据库

    actionLog := &model.ActionLogTab{XXXXXX}

    err := CreateActionLog(actionLog)//创建测试的数据记录

    assert.Nil(suite.T(),err)

    logs,count,err := FetchActionLogs(repo,repo.MerchantID,actionLog.SheetID,actionLog.SheetType,1,1)//需要测试的函数

    assert.Nil(suite.T(),err)

    assert.Equal(suite.T(),logs[0].OperationTime,actionLog.OperationTime)//验证函数的正确性

 

    err = repo.MerchantDB().Delete(actionLog).Error//删除掉测试的数据库记录

    assert.Nil(suite.T(),err)}

以上就是如何使用go优雅地撰写单元测试的详细内容,更多文章请关注木庄网络博客!!

相关阅读 >>

kubernetes学习笔记之csi external provisioner源码解析

分享十个优秀的 Go 类库

Golang之sync.pool对象池对象重用机制总结

手撸Golang 仿spring ioc/aop 之9 扫码4

Go语言标准库之strconv

一周 Go world 新鲜事

[系列] - Go-gin-api 路由中间件 - 签名验证(七)

Go学习五·切片

手撸Golang 基本数据结构与算法 插入排序

Golang flag是什么

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...