首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【初识Go】| Day12 单元测试

【初识Go】| Day12 单元测试

作者头像
yussuy
修改于 2020-12-28 03:36:02
修改于 2020-12-28 03:36:02
3150
举报

Maurice Wilkes,第一个存储程序计算机EDSAC的设计者,1949年他在实验室爬楼梯时有一个顿悟。在《计算机先驱回忆录》(Memoirs of a Computer Pioneer)里,他回忆到:“忽然间有一种醍醐灌顶的感觉,我整个后半生的美好时光都将在寻找程序BUG中度过了”。肯定从那之后的大部分正常的码农都会同情Wilkes过分悲观的想法,虽然也许会有人困惑于他对软件开发的难度的天真看法。

现在的程序已经远比Wilkes时代的更大也更复杂,也有许多技术可以让软件的复杂性可得到控制。其中有两种技术在实践中证明是比较有效的。第一种是代码在被正式部署前需要进行代码评审。第二种则是测试,也就是本章的讨论主题。

我们说测试的时候一般是指自动化测试,也就是写一些小的程序用来检测被测试代码(产品代码)的行为和预期的一样,这些通常都是精心设计的执行某些特定的功能或者是通过随机性的输入待验证边界的处理。

Go语言的测试技术是相对低级的。它依赖一个go test测试命令和一组按照约定方式编写的测试函数,测试命令可以运行这些测试函数。编写相对轻量级的纯测试代码是有效的,而且它很容易延伸到基准测试和示例文档。

在实践中,编写测试代码和编写程序本身并没有多大区别。我们编写的每一个函数也是针对每个具体的任务。我们必须小心处理边界条件,思考合适的数据结构,推断合适的输入应该产生什么样的结果输出。编写测试代码和编写普通的Go代码过程是类似的;它并不需要学习新的符号、规则和工具。

在日常开发中,我们通常需要针对现有的功能进行单元测试,以验证开发的正确性。 在go标准库中有一个叫做testing的测试框架,可以进行单元测试,命令是go test xxx

测试文件通常是以xx\_test.go命名,放在同一包下面。

初探Go单元测试

现在假设现在需求是:完成两个复数相加,我们只需要一个函数便可以完成该任务。

在开发中,我们需要对该函数进行功能测试,如何快速进行单元测试呢?

鼠标放在函数上右键,选择GO:Generate Unit Tests For Function即可生成file_test.go文件。

随后在测试文件中完成测试功能即可,可以进入code/utest里面的complex_test进行单元测试。

单测要点

第一:单元测试的时候,如果有一些打印log信息,我们运行xxx_test.go是输出不出来的,此时需要使用:

代码语言:txt
AI代码解释
复制
go test xxx\_test.go -v

使用-v参数可以帮助我们解决此问题。

第二:单测覆盖率,覆盖率可以简单理解为进行单元测试mock的时候,能够覆盖的代码行数占总代码行数的比率,当然是高一点要好些。可以通过-cover指定

代码语言:txt
AI代码解释
复制
go test xxx\_test -v -cove

第三:在上述提到的测试方法中我们使用的是(table-driven tests)表格驱动型测试,我们看一下代码:

代码语言:txt
AI代码解释
复制
tests := []struct {

    name string

    args args

    want \*Complex

}{

    // TODO: Add test cases.

    {

        name: "",

        args: args{

            a: Complex{

                Real: 1.0,

                Imag: 2.0,

            },

            b: Complex{

                Real: 1.0,

                Imag: 1.0,

            },

        },

        want: &Complex{

            Real: 2.0,

            Imag: 3.0,

        },

    },

}

在TODO里面我们可以填写很多单元测试样例。

基准测试

基准测试函数名字必须以Benchmark开头,代码在xxx_test.go中。具体如下:

代码语言:txt
AI代码解释
复制
func BenchmarkComplex(t \*testing.B) {

    for i := 0; i < t.N; i++ {

        fmt.Sprintf("hello")

    }

}

运行:

代码语言:txt
AI代码解释
复制
go test -benchmem -run=. -bench=.

输出:

goos: linux

goarch: amd64

BenchmarkComplex-8       20542494            58.9 ns/op           5 B/op           1 allocs/op

PASS

ok      \_/home/light/go\_dev/go-talent/code/utest    1.272s

20542494表示for循环的测试,58.9表示每次需要花费58.9纳秒。 -benchmem可以提供每次操作分配内存的次数,以及每次操作分配的字节数。 allocs/op 表示每次操作从堆上分配内存的次数。B/op 表示每次操作分配的字节数。

mock/stub测试

gomock是官方提供的mock框架,同时有mockgen工具来辅助生成测试代码。

https://github.com/golang/mock

需要自己先安装一下:

代码语言:txt
AI代码解释
复制
go get -u github.com/golang/mock/gomock

go get -u github.com/golang/mock/mockgen

下面以DB为例,有如下接口:

代码语言:txt
AI代码解释
复制
type DB interface {

    Get(key int) (string, error)

}

我们想通过Get接口返回对应value。于是写出了下面这个函数:

代码语言:txt
AI代码解释
复制
func GetValue(db DB, key int) (string, error) {

    value, err := db.Get(key)

    if err != nil {

        return "", errors.New("fail")

    }

    return value, nil

}

我们现在比较关心的是当前我们写的函数是否正确,而中间调用了Get接口,该接口我们可以进行mock,首先使用下面命令:

代码语言:txt
AI代码解释
复制
mockgen -source=db.go -destination=db\_mock.go -package=db

随后在单元测试文件中进行go mock即可。

代码语言:txt
AI代码解释
复制
func TestGetValue(t \*testing.T) {

    ctrl := gomock.NewController(t)

  defer ctrl.Finish()



    m := NewMockDB(ctrl)

    m.EXPECT().Get(gomock.Eq(1)).Return("我是1的value", nil)



    if v, err := GetValue(m, 1); err != nil {

        t.Error(err)

    } else {

        t.Log(v)

    }

}

其中比较重要的是打桩(stubs):

代码语言:txt
AI代码解释
复制
m.EXPECT().Get(gomock.Eq(1)).Return("我是1的value", nil)

这一行我们mock掉了Get接口,假设其返回字符串(我是1的value)与nil,随后进行逻辑测试。

这种方式的好处是不直接依赖的实例,而是使用依赖注入降低耦合性。

直接替换

在1.4中我们是需要进行打桩并使用mockgen才可以完成一些复杂api的测试的,那有没有更简单的方法呢,例如:直接替换函数为想要的函数,在github上有monkey库为我们使用。

输入下面命令进行安装:

go get github.com/bouk/monkey

假设有Get接口的实现者是Handler,那么我们直接使用monkey进行方法替换,把Get方法替换为我们自己的,仅此一步搞定单元测试,非常方便。

代码语言:txt
AI代码解释
复制
func TestGetValue1(t \*testing.T) {

    var h \*Handle

    monkey.PatchInstanceMethod(reflect.TypeOf(h), "Get", func(handler \*Handler, key int) (string, error) {

        return "我是1的value", nil

    })

    if v, err := GetValue(h, 1); err != nil {

        t.Error(err)

    } else {

        t.Log(v)

    }

}

浏览器实时测试

接下来引入一个比较方便的单元测试框架,可以在浏览器进行实时查看单元测试结果。只需要三步即可。

第一步:

代码语言:txt
AI代码解释
复制
go get github.com/smartystreets/goconvey

第二步:

代码语言:txt
AI代码解释
复制
$GOPATH/bin/goconvey

第三步:

代码语言:txt
AI代码解释
复制
http://localhost:8080

此时在页面可以看到下面这个。

除此之外,我们看到使用vscode生成的单元测试(table-driven tests)贼丑,那么我们可以使用convey进行单测。

代码语言:txt
AI代码解释
复制
func TestSpec(t \*testing.T) {

    // Only pass t into top-level Convey calls

    Convey("Given some integer with a starting value", t, func() {

        x := 1

        Convey("When the integer is incremented", func() {

            x++

            Convey("The value should be greater by one", func() {

                So(x, ShouldEqual, 2)

            })

        })

    })

}

使用convey进行包裹起来好看的一匹。

参考资料

https://github.com/datawhalechina/go-talent/blob/master/11.%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95.md

http://shouce.jb51.net/gopl-zh/ch11/ch11.html

本文系转载,前往查看

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

本文系转载,前往查看

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Golang 单元测试合集整理,(我最常用 gomonkey)欢迎收藏
无论写什么样的语言,单元测试都是必不可少的,它可以极大的提高我们的代码质量,减少各种低级错误和 bug
阿兵云原生
2023/09/14
2.1K0
Golang 单元测试合集整理,(我最常用 gomonkey)欢迎收藏
Golang 单元测试详尽指引
文末有彩蛋。 作者:yukkizhang,腾讯 CSIG 专项技术测试工程师 本篇文章站在测试的角度,旨在给行业平台乃至其他团队的开发同学,进行一定程度的单元测试指引,让其能够快速的明确单元测试的方式方法。 本文主要从单元测试出发,对Golang的单元测试框架、Stub/Mock框架进行简单的介绍和选型推荐,列举出几种针对于Mock场景的最佳实践,并以具体代码示例进行说明。 一、单元测试 1. 单元测试是什么 单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向
腾讯技术工程官方号
2020/10/26
4.7K0
优雅的使用Go进行单元测试
现在我们想测试Target函数,但是由于调用的A函数依赖于自己的某个函数,这里就是A调用了rpc接口拉别人接口数据,我们想mockA接口的目标是,想直接拿到A返回的数据即可,直接采用gomock方式,行不通,自己测试了一下,发现要不断的mock 别人接口所依赖的其他接口,非常麻烦,通过注入代码或者后面第三种方式替换函数即可解决。
公众号guangcity
2020/07/20
3K0
一文说尽Golang单元测试实战的那些事儿
导语 | 单元测试,通常是单独测试一个方法、类或函数,让开发者确信自己的代码在按预期运行,为确保代码可以测试且测试易于维护。腾讯后台开发工程师张力结合了公司级漏洞扫描系统洞犀在DevOps上探索的经验,以Golang为例,列举了编写单元测试需要的工具和方法,然后针对写单测遇到的各种依赖问题,详细介绍了通过Mock的方式解决各种常用依赖,方便读者在写go语言UT的时候,遇到依赖问题,能够快速找到解决方案。最后再和大家探讨一下关于单元测试上的一些思考。 一、前言 单元测试,通常是单独测试一个方法、类或函数
腾讯云开发者
2021/07/28
1.5K0
Golang单元测试
Go提供了test工具用于代码的单元测试,test工具会查找包下以_test.go结尾的文件,调用测试文件中以 Test或Benchmark开头的函数并给出运行结果
仙人技术
2021/08/31
8420
Golang单元测试
Golang单元测试系列-如何更好的写测试用例
前面写了快速上手,会非常快速的创建测试用例,搭建一个单元测试的架子,但是如何来更好的写测试用例呢?
jerryteng
2022/06/16
1.7K0
Golang单元测试系列-如何更好的写测试用例
Go每日一库之91:gomock
testing包里 介绍了 Go 语言中单元测试的常用方法,包括子测试(subtests)、表格驱动测试(table-driven tests)、帮助函数(helpers)、网络测试和基准测试(Benchmark)等。这篇文章介绍一种新的测试方法,mock/stub 测试,当待测试的函数/对象的依赖关系很复杂,并且有些依赖不能直接创建,例如数据库连接、文件I/O等。这种场景就非常适合使用 mock/stub 测试。简单来说,就是用 mock 对象模拟依赖项的行为。
luckpunk
2023/09/30
5090
手把手教你如何进行 Golang 单元测试
点击上方蓝字,发现更多精彩 导语 本篇是对单元测试的一个总结,通过完整的单元测试手把手教学,能够让刚接触单元测试的开发者从整体上了解一个单元测试编写的全过程。最终通过两个问题,也能让写过单元测试的开发者收获单测执行时的一些底层细节知识。 引入 随着工程化开发在司内大力的推广,单元测试越来越受到广大开发者的重视。在学习的过程中,发现网上针对 Golang 单元测试大多从理论角度出发介绍,缺乏完整的实例说明,晦涩难懂的 API 让初学接触者难以下手。 本篇不准备大而全的谈论单元测试、笼统的介绍 Golang
腾讯VTeam技术团队
2021/06/02
1.5K0
Go单测系列4—mock接口测试
这是Go语言单元测试从零到溜系列教程的第3篇,介绍了如何在单元测试中使用gomock和gostub工具mock接口和打桩。
luckpunk
2023/09/10
7490
Golang 单元测试 - 逻辑层
前面我们完成了最麻烦的数据层的单元测试,今天我们来看看单元测试中最容易做的一层,数据逻辑层,也就是我们通常说的 service 或者 biz 等,是描述具体业务逻辑的地方,这一层包含我们业务最重要的逻辑。
LinkinStar
2023/02/22
5450
白话Golang单元测试
最近学习某个 Golang 单元测试的课程,发现其中推荐使用 gomonkey 这种黑科技,让人略感意外,毕竟在软件开发领域,诸如依赖注入之类的概念已经流传了几十年了,本文希望通过一个例子的演化过程,来总结出 Golang 单元测试的最佳实战。
LA0WAN9
2021/12/14
5200
go 单元测试进阶篇
腾讯云数据库团队
2017/01/05
9K2
go 单元测试进阶篇
Golang 测试教程
How to write test with golang 代码示例 TDD(Test-Driven development) 测试驱动开发 内置的 testing 库 、 表格驱动、样本测试、TestMain 第三方:goconvey Monkey 猴子补丁 数据库 mock travisCI 代码覆盖率 TDD 快速实现功能 再设计和重构 软件测试 在指定的条件下,操作程序,发现程序错误 单元测试 对软件的组成单元进行测试,最小单位:函数 包含三个步骤: 指定输入 指定预期 函数结果和指定的预期
谢伟
2019/03/11
1.7K0
Golang 测试教程
Go:微服务架构下的单元测试(基于 Ginkgo、gomock 、Gomega)
本文主要使用 Ginkgo[2] 、gomock[3] 、Gomega[4] 工具来实现单元测试,之前不了解的同学,可以先熟悉一下相关文档。
Freedom123
2024/03/29
6430
Go:微服务架构下的单元测试(基于 Ginkgo、gomock 、Gomega)
Go 单元测试之mock接口测试
gomock 是一个 Go 语言的测试框架,在实际项目中,需要进行单元测试的时候。却往往发现有一大堆依赖项。这时候就是 Gomock 大显身手的时候了,用于编写单元测试时模拟和测试依赖于外部服务的代码。它允许你创建模拟对象(Mock Objects),这些对象可以预设期望的行为,以便在测试时模拟外部依赖,通常使用它对代码中的那些接口类型进行mock。
贾维斯Echo
2024/04/19
2740
Go 单元测试之mock接口测试
go 单元测试基本篇
腾讯云数据库团队
2017/01/04
4.6K0
go 单元测试基本篇
使用 Gomock 进行单元测试
在实际项目中,需要进行单元测试的时候。却往往发现有一大堆依赖项。这时候就是 Gomock 大显身手的时候了
李海彬
2018/12/24
3.7K0
Go 单元测试
代码 bug 总是在所难免, 越早发现问题解决成本越低, 单测可以尽早的暴露错误。提高代码之路,使得项目更高质量的交付。 起码有三个优点:
王小明_HIT
2022/01/06
1.1K0
Go语言单元测试
学习Golang的时候遇到了一些单元测试问题,发现有些工具是真的好用,就记录在此,主要包括monkey、convey,还有数据库Mock等。
有财君
2023/03/21
7260
Go语言单元测试
Go 单元测试从 0 到 1
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。
恋喵大鲤鱼
2021/07/23
7550
相关推荐
Golang 单元测试合集整理,(我最常用 gomonkey)欢迎收藏
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档