前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为啥开源项目里面那么多_test文件?

为啥开源项目里面那么多_test文件?

作者头像
小锟哥哥
发布2022-05-10 09:06:16
4900
发布2022-05-10 09:06:16
举报
文章被收录于专栏:GoLang全栈

在看开源项目的同学,如果你已经开始注意 _test 文件了的话,那么恭喜你,你将开启单元测试的大门了。

关于单元测试,Go 语言它有一套属于自己的单元测试和性能测试系统。

相比其他语言,这块有着非常强的优势,我们只需要写很少的代码就能实现对代码的测试。

这篇文章我们主要讲解单元测试,下一篇我们再讲基准测试。

什么是单元测试?

大家可还记得我们读书时,翻开《语文》书目录的时候,总能看到第一单元,第二单元么?

像下面这张图:

图片来自网络

你会发现,一本书作者把它被分成了很多个单元,当我们学完所有单元就意味着这个学期学完了,这本书学完了。

我们的程序也是这样,我们的一个项目,大都会被分成不同的模块,不同模块里面又会有不同的单元。

当我们的每一个单元都测试OK,也就意味着,这个项目在正常情况下使用,应该没啥问题了。

当然也有不正常的时候,那就说明卡BUG了,自求多福吧,哈哈。

所以在大型项目里面,单元测试是必不可少的,小项目就看项目需要了。

怎么创建?

我们只需要在我们的工程里面创建以 _test 结尾的 go 文件即可,一个单元测试文件就创建好了。

如果是在 GoLand 里面他会自动给识别,加上特殊的标记,比如下面这样的:

大部分 Go语言的开源项目,这样的文件就特别多,比如这样:

这是 kubernetes 的 Github 截图。

开始编写

首先我们需要写一个简单的业务文件,方便我们去测试,于是我新建了一个目录 utils,然后新建一个 string.go 文件:

代码语言:javascript
复制
package utils

// JointString 拼接字符串
func JointString(a string,b string) string {
 return a+b
}

我写了一个非常简单的方法,就是拼接两个字符串。

然后我们再建一个单元测试文件。

我们喜欢把单元测试的文件名和被测试的文件关联起来,喜欢在测试的文件后面加 _test ,所以我们的文件名 就是 string_test.go 。

注意点:

文件建好之后,就需要在里面去编写我们的测试代码了。

1、其实我们的单元测试代码,和我们的普通代码没太大的区别,你正常写就好了。

2、唯一的区别就是,我们需要用到 testing 包里面的相关 API 来进行干预测试结果。

3、同时方法名必须要 Test 开头。

当然我们也比较喜欢把测试方法和被测试的方法关联起来(非硬性规定),于是我们就这样写一个最简单的测试代码:

代码语言:javascript
复制
package utils

import (
 "fmt"
 "testing"
)

func TestJointString(t *testing.T) {
 fmt.Println(JointString("a","b"))
}

这里我们还没用到任何的 testing 里面的API,只是在测试方法里面调用了我们的 JointString 方法。

运行起来

如果你用的 GoLand 开发,就可以直接点击方法旁边的绿色图标即可运行:

你也可以在命令行里面运行,cd 到我们的 utils 目录下面,执行 go test 即可:

代码语言:javascript
复制
go test -v

// 执行结果
$ go test -v
=== RUN   TestJointString
ab
--- PASS: TestJointString (0.00s)
PASS
ok      map-demo/utils  0.328s

-v 是让控制台输出测试详细的流程。

单元测试进阶

现在你已经会了基本的单元测试创建方法,接下来进阶下。

我们需要对我们的测试结果进行预判,否则只是输出一个结果那肯定达不到测试的目的。

这就需要了解下我们的 testing.T 里面的 API 了,我们常用的方法有:

方法

备注

Log

打印日志,同时结束测试

Logf

格式化打印日志,同时结束测试

Error

打印错误日志,同时结束测试

Errorf

格式化打印错误日志,同时结束测试

Fatal

打印致命日志,同时结束测试

Fatalf

格式化打印致命日志,同时结束测试

接下来我们进行改造我们的测试方法:

代码语言:javascript
复制
func TestJointString(t *testing.T) {
 if JointString("a","b")!="ab" {
  t.Error("与我们预判的结果不一致")
 }
 // 故意写一个错误的预判
 if JointString("g","b")!="gob" {
  t.Error("与我们预判的结果不一致")
 }
}

//执行结果
$ go test  -v
=== RUN   TestJointString
    string_test.go:13: 与我们预判的结果不一致
--- FAIL: TestJointString (0.00s)
FAIL
exit status 1
FAIL    map-demo/utils  1.851s

你会发现测试结果就是 FAIL 了。

再次进阶

我们一般对一个方法不会是只有一两个预判。

如果有 N 个预判,你还继续使用上面这种 if 来判断,会有点 LOW。

于是我们可以对我们的测试代码再次升级。

我们可以模拟一个把测试数据和预判结果放到一个二维数组里面来 for 遍历,这种方式我们也叫 表驱动测试模式

上代码:

代码语言:javascript
复制
func TestJointString1(t *testing.T) {
 type args struct {
  a string
  b string
 }
 tests := []struct {
  name string
  args args
  want string
 }{
  // 这里编写我们的预判逻辑
  {"testA", args{"d","v"}, "dv"},
  {"testB", args{"c","d"}, "cd"},
 }
 for _, tt := range tests {
  t.Run(tt.name, func(t *testing.T) {
   if got := JointString(tt.args.a, tt.args.b); got != tt.want {
    t.Errorf("JointString() = %v, want %v", got, tt.want)
   }
  })
 }
}

// 执行结果
$ go test  -v
=== RUN   TestJointString1
=== RUN   TestJointString1/testA
=== RUN   TestJointString1/testB
--- PASS: TestJointString1 (0.00s)
    --- PASS: TestJointString1/testA (0.00s)
    --- PASS: TestJointString1/testB (0.00s)
PASS
ok      map-demo/utils  0.437s

我们每次只需要调整我们中间的预判逻辑即可。

你学废了么?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-02-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 GoLang全栈 微信公众号,前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是单元测试?
  • 怎么创建?
  • 开始编写
    • 注意点:
      • 运行起来
      • 单元测试进阶
      • 再次进阶
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档