原创

go 单元测试基本篇

作者:熊训德

go 语言本身内置了一套相对轻量级的测试框架,通过 testing 库和 go test 命令支持单元测试。本篇文档主要介绍使用 go 语言 testing 包进行单元测试方法,以及一些在编写单元测试过程遇到的坑。

在 go 中使用单元测试时,在同需测试的源文件目录下增加XXX_test.go(XXX是源文件名)文件即可。如用Intelij IDEA还会帮你把包设置为XXX_test(XXX是源包名),这样可以防止测试依赖的包时的相互依赖,go把这个称作扩展测试包(External test packages)。

下面举一个栗子就很容易理解:

需要测试的函数是一个查询函数,它的功能是通过http协议向异构的某个模块查询信息。因为对方这个模块的接口是可能变更的,所以使用在这个公共函数中使用单元测试不仅可以测试当前代码逻辑,也可帮助往后再开发时的效率。

被测源代码如下:

可以看到被测的公共函数就只有一个入参,两个出参,还算比较简单。

利用go自带框架,最简单的单测代码即可如下:

然后在同目录下输入命令

$go test -v XXX_test.go

其中,-v选项可用于打印每个测试函数的名字和运行时间。

正常情况下,是会出现单测成功或者失败的信息。但这个例子有点不一样,终端会出现这样的错误:

错误里提及component.url配置项并未设置,这是因为这个例子需要依赖外部配置文件,配置文件有设置component.url。

这里,可以使用-o选项。在某些依赖配置文件的情况下-o很有用

go test命令会先生成一个测试可执行文件,如果没-o会是一个临时目录(/tmp/go-build266773839/command-line-arguments),然后在这个临时目录下执行测试的可执行文件,如果使用-o选项:

可以看到可执行文件就会指定在生成可执行测试文件的地方执行(也即是-o指定的目录下执行)。

从这个示例中可以看到,testing包提供了Logf和Error等方法来帮助提高测试效率,如果是Error方法的分支被执行了,则这组测试示例会失败,Logf则是在标准输出上输出log信息。

示例到这里,单测代码也写好了,单测执行也成功了,是否意味着单测就完成。其实不是,个人认为单测的目的主要在于在最小的模块内覆盖所有可能逻辑测试,使得更复杂的模块集成后降低bug的风险。要覆盖被测模块中更多的代码,则需要更多的参数组(测试用例)。实现这个最简单的方法就是多写几个TestXXX,go语言提供了表格驱动的测试方式,把所有测试数据合并到了一个测试中的表格中再集中测试。

go语言中所谓的表格驱动,就是把输入和预期输出做成一个表格,很容易向表格添加新的测试数据,并且后面的测试逻辑也没有冗余,这样我们可以有更多的精力地完善错误信息,比如上例中单元测试是写成类似形式:

tests结构即是测试表格,这样即可以测试是否和预期的输入及输出一致。但是因为本示例中被测函数中的返回值复杂,为了简化单元测试(返回的error不易比对),最终的单元测试是使用t.Logf来查看:

func TestQueryClusterVip(t *testing.T){
    darwinService := component.NewDarwinService(9)
        //测试表格
    var tests = []struct {
        input int64
        rsp *QueryClusterGroupVipRsp
        err error
    }{
        {900086,&QueryClusterGroupVipRsp{Vip:"10.66.188.221"},nil},
        {0,nil,nil},
    }

    for _,test := range tests{
        rsp,err := darwinService.QueryClusterVip(test.input)
        t.Logf("rsp:%v",rsp)
        t.Logf("err:%v",err)
    }
}

go自带的测试框架还提供了测试覆盖率和基准测试两个工具帮助查看编写代码和单测的质量和效率,详见

如果使用惯了了xUnit(JUnit、CppUnitdeng)的单元测试,开始使用go自带的测试框架,会觉得怪怪的,心里满是疑问,为哈单测连都没有断言,表示不服,但是开源社区的gocheck提供了。像Assert简直新手拈来:

func Test(t *testing.T) { TestingT(t) }

type MyTest struct{}

var _ = Suite(&MyTest{})

func (s *Test) TestHelloWorld(c *C) {
    c.Assert(42, Equals, "42")
    c.Assert(io.ErrClosedPipe, ErrorMatches, "io: .*on closed pipe")
    c.Check(42, Equals, 42)
}

这样让单测可以看起来简洁不少,更详细功能和用法可查看其官网

一般来说使用go语言自带的测试框架可以使用单测覆盖60%以上的代码。如果代码中并没有自带http请求,那么测试的时候就需要自己编写代码去构造http请求,。还有一种很常见的场景就是需要测试的代码中依赖了外部资源,而这些外部资源不像本例单测环境里不能提供或者提供特别繁琐,比如网络资源、DB资源等,就需要使用其他测试框架中常用的mock,coverage等技术,而这些go自带测试框架并不提供。

下一篇将介绍以伪对象(Mock,Stub等)核心技术为主的第三方测试框架来补充,以拟补go语言自带的测试框架的不足。

相关推荐

go单元测试进阶篇

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

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • MySQL 内核深度优化

    MYSQL 数据库适用场景广泛,相较于 Oracle 、DB2 性价比更高,Web 网站、日志系统、数据仓库等场景都有 MYSQL 用武之地,但是也存在对于事务...

    腾讯云数据库团队
  • 如何登录腾讯云数据库

    本文主要介绍了使用命令行方式登录以及使用云数据库管理界面登录这两种实例登录腾讯云数据库的步骤。

    腾讯云数据库团队
  • 数据库最佳实践: DBA 小马如何走上升值加薪之路?

    腾讯云数据库团队的同学结合自身的成长经历,用漫画的形式为我们分享了一位DBA是如何从菜鸟成长为大神,走上升职加薪,迎娶白富美之路的。

    腾讯云数据库团队
  • 2019裁员潮,测试被裁了能干什么?

    这个裁员名单只是所有裁员公司的一角。各个行业的独角兽公司,既是媒体关注的焦点,也是代表了行业风向的指针。 2019年的互联网,已经过了蓬勃发展期,接...

    用户2149234
  • YIYA语义测试方面总结探讨

    1 产品介绍 YIYA是一个语音助手,根据用户输入语音内容,进行对应的操作或返回对应的结果,比如询问天气,返回所在地的天气结果。目前使用在微桌面及TOS手表中。...

    腾讯移动品质中心TMQ
  • 2019裁员潮,测试被裁了能干什么?

    这个裁员名单只是所有裁员公司的一角。各个行业的独角兽公司,既是媒体关注的焦点,也是代表了行业风向的指针。 2019年的互联网,已经过了蓬勃发展期,接...

    用户2149234
  • 软件测试工程师承受的压力(二)

    其他两点:4.收入的压力 5.家庭的压力,因为所有职场人都会有遇到,暂时不说了。

    muntainyang
  • Python 测试开发从入门到高手成长之路

    在“质量第一,效率为王”的移动互联网和大数据时代,互联网 IT 技术团队为了应对产品快速迭代要求,就必须具备持续交付的能力。而在测试这个环节,就意味着必须拥有自...

    测试小兵
  • Beyond Accuracy:Behavioral Testing of NLP Models with Checklist 论文阅读

    本文主要介绍以及翻译一篇 ACL2020 Best Paper Beyond Accuracy:Behavioral Testing of NLP Models...

    mathor
  • 灰盒web安全检测技术

    灰盒web安全检测 在传统的应用测试方法中, 灰盒测试是介于白盒测试与黑盒测试之间。灰盒web安全检测依然遵循灰盒测试概念, 但只关注代码实现的安全部分。web...

    安恒信息

扫码关注云+社区

领取腾讯云代金券