前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang单元测试系列-如何更好的写测试用例

Golang单元测试系列-如何更好的写测试用例

原创
作者头像
jerryteng
修改2022-06-16 19:45:38
1.5K0
修改2022-06-16 19:45:38
举报
文章被收录于专栏:jerryteng的专栏jerryteng的专栏

前面写了快速上手,会非常快速的创建测试用例,搭建一个单元测试的架子,但是如何来更好的写测试用例呢?

我们如何来提升 单测的交互呢 ?

使用goconvey提升单测交互

GoConvey是一个非常好用的Go测试框架,它直接与go test集成,提供了很多丰富的断言函数,能够在终端输出可读的彩色测试结果,还支持全自动的Web UI。

当然我们大部分时间是不使用web UI的,都是流水线集成测试。

下面使用goconvey对从身份证号获取出生日期的函数实现单测

代码语言:javascript
复制
package util

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestGetBirthdayFromIdNumber(t *testing.T) {
	Convey("测试从身份证号获取YYYY-MM-DD格式的出生日期", t, func() {
		// 注意这里的代码会被执行多次
		// ......

		Convey("校验码为X的正常身份证号", func() {
			var (
				idNumber = "37078620000101023X"
				want     = "2000-01-01"
			)
			got := GetBirthdayFromIdNumber(idNumber)
			So(got, ShouldEqual, want)
		})
		Convey("入参非身份证号", func() {
			var (
				idNumber = "20000101"
			)
			got := GetBirthdayFromIdNumber(idNumber)
			So(got, ShouldBeEmpty)
		})
	})
}

 说明:

  1. 这里在导入goconvey包的时候通过“.”,省略了调用包内函数时的包名前缀,是goconvey推荐的写法。
  2. convey函数支持平铺罗列,也支持二层、三层嵌套,用于更细粒度拆分单测用例,一般写两层就够了。注意只有外层需要将testing对象t传入进去,内层不需要。
  3. 需要注意外层的代码会随着内层的convey函数执行而执行。
  4. goconvey提供了So断言函数,和很多断言规则,例如ShouldEqual(判断完全相等)、ShouldResemble(相当于reflect.deepEqual,用于map、slice、指针类型的相等判断)、ShouldBeNil(判断等于nil)、ShouldBeLessThan(数字类型大小比较)、ShouldHappenBefore(时间类型判断)等,具体可查阅官方文档。同时,goconvey也支持自定义断言规则,用于自定义判断规则。

执行go test -v -run Xxx,获取单测结果,可以看到测试用例层级展示,每个So断言对应一个√,出错时可以方便的定位到失败的断言。

mock依赖

如果我们依赖数据库或者其他的接口,该如何来mock 呢 ?

我们现在一般都是用gomock来mock代码,使用gomock的前提是,在你实现代码的时候必须很好的去抽象,把所有的数据库代码或者接口代码都抽象成go的接口,之后通过 mockgen 来生成 gomock的代码。就像下面的代码: MysqlService 抽象mysql操作

使用gomock给接口打桩

gomock是Go官方提供的测试框架,它可以对代码中的接口类型进行mock,方便编写单元测试。

如果我们平时遵守依赖倒置原则编写代码,那么使用gomock就会很方便。

需要写单测的业务代码如下,可以看到我们GetStudentTermResult方法中包含了两个mysql查询,按照上文说的单测设计原则,这是需要被mock的行为。

file - student.go

代码语言:javascript
复制
package school

import (
	"GoTesting/util"
)

// StudentService 学生模块service层
type StudentService struct {
	m MysqlService
}

// GetStudentTermResult 获取学生学期总结,包括期末成绩、挂科情况
func (s *StudentService) GetStudentTermResult(sId, term string) (*TermResultModel, error) {
	// 学生信息
	name, err := s.m.GetStudentName(sId)
	if err != nil {
		return nil, err
	}
	// 获取学期的时间范围
	sTime, eTime := util.GetTermTimeRange(term)
	// 查询指定时间段内的学生所有成绩
	scores, err := s.m.GetStudentScores(sId, sTime, eTime)
	if err != nil {
		return nil, err
	}
	// 统计个人通过率
	courseNumber := int32(len(scores)) // 课程数量
	passNumber := int32(0)             // 及格课程数量
	for _, score := range scores {
		if score >= 60 {
			passNumber++
		}
	}
	return &TermResultModel{
		Name:         name,
		Term:         term,
		Scores:       scores,
		CourseNumber: courseNumber,
		FailedNumber: courseNumber - passNumber,
		PassRate:     float32(passNumber) / float32(courseNumber),
	}, nil
}

file - mysql.go

代码语言:javascript
复制
package school

// MysqlService 抽象mysql操作
type MysqlService interface {
	GetStudentName(sId string) (string, error)
	GetStudentScores(sId, sTime, eTime string) (map[string]float32, error)
}

type Mysql struct {
}

// GetStudentName 获取学生姓名
func (m *Mysql) GetStudentName(sId string) (n string, err error) {
	// 从mysql存储中select学生表的具体逻辑
	// ......
	return
}

// GetStudentScores 查询学生指定时间段内的所有考试成绩
func (m *Mysql) GetStudentScores(sId, sTime, eTime string) (scores map[string]float32, err error) {
	// 从mysql存储中select成绩表的具体逻辑
	// ......
	return
}

接下来通过gomock实现单测。

首先使用mockgen命令自动生成mock代码,

代码语言:javascript
复制
 mockgen -destination file_mock.go -package school -source file.go

 下图就是自动生成的mock代码,文件头部会自动带上 DO NOT EDIT. 编辑器也会提升我们不需要编辑,每次调整都使用上面的命令重新生成一遍。

这样就很好的解决外部依赖的问题。

这样在 为我们的业务代码:GetStudentTermResult 编写测试用例的时候,就可以直接mock MySQL的操作,测试就非常方便,我们只需要关注 测试业务代码本身是否符合预期就可以了。

下一次我们再说一下,如何更快速的编写测试用例。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用goconvey提升单测交互
  • mock依赖
    • 使用gomock给接口打桩
    相关产品与服务
    云数据库 SQL Server
    腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档