文档章节

Go 子测试使用说明

恋恋美食
 恋恋美食
发布于 02/12 11:40
字数 1461
阅读 5
收藏 0
Go

简介

简单的说,子测试提供一种在一个测试函数中执行多个测试的能力,比如原来有TestA、TestB和TestC三个测试函数,每个测试函数执行开始都需要做些相同的初始化工作,那么可以利用子测试将这三个测试合并到一个测试中,这样初始化工作只需要做一次。

除此之外,子测试还提供了诸多便利,下面我们逐一说明。

简单例子

我们先看一个简单的例子,以便快速了解子测试的基本用法。

package gotest_test

import (
    "testing"
    "gotest"
)

// sub1 为子测试,只做加法测试
func sub1(t *testing.T) {
    var a = 1
    var b = 2
    var expected = 3

    actual := gotest.Add(a, b)
    if actual != expected {
        t.Errorf("Add(%d, %d) = %d; expected: %d", a, b, actual, expected)
    }
}

// sub2 为子测试,只做加法测试
func sub2(t *testing.T) {
    var a = 1
    var b = 2
    var expected = 3

    actual := gotest.Add(a, b)
    if actual != expected {
        t.Errorf("Add(%d, %d) = %d; expected: %d", a, b, actual, expected)
    }
}

// sub3 为子测试,只做加法测试
func sub3(t *testing.T) {
    var a = 1
    var b = 2
    var expected = 3

    actual := gotest.Add(a, b)
    if actual != expected {
        t.Errorf("Add(%d, %d) = %d; expected: %d", a, b, actual, expected)
    }
}

// TestSub 内部调用sub1、sub2和sub3三个子测试
func TestSub(t *testing.T) {
    // setup code

    t.Run("A=1", sub1)
    t.Run("A=2", sub2)
    t.Run("B=1", sub3)

    // tear-down code
}

本例中TestSub()通过t.Run()依次执行三个子测试。t.Run()函数声明如下:

func (t *T) Run(name string, f func(t *T)) bool

name参数为子测试的名字,f为子测试函数,本例中Run()一直阻塞到f执行结束后才返回,返回值为f的执行结果。 Run()会启动新的协程来执行f,并阻塞等待f执行结束才返回,除非f中使用t.Parallel()设置子测试为并发。

本例中TestSub()把三个子测试合并起来,可以共享setup和tear-down部分的代码。

我们在命令行下,使用-v参数执行测试:

E:\OpenSource\GitHub\RainbowMango\GoExpertProgrammingSourceCode\GoExpert\src\gotest>go test subunit_test.go -v
=== RUN   TestSub
=== RUN   TestSub/A=1
=== RUN   TestSub/A=2
=== RUN   TestSub/B=1
--- PASS: TestSub (0.00s)
    --- PASS: TestSub/A=1 (0.00s)
    --- PASS: TestSub/A=2 (0.00s)
    --- PASS: TestSub/B=1 (0.00s)
PASS
ok      command-line-arguments  0.354s

从输出中可以看出,三个子测试都被执行到了,而且执行次序与调用次序一致。

子测试命名规则

通过上面的例子我们知道Run()方法第一个参数为子测试的名字,而实际上子测试的命名规则为:"<父测试名字>/<传递给Run的名字>"。比如,传递给Run()的名字是“A=1”,那么子测试名字为“TestSub/A=1”。这个在上面的命令行输出中也可以看出。

过滤筛选

通过测试的名字,可以在执行中过滤掉一部分测试。

比如,只执行上例中“A=*”的子测试,那么执行时使用-run Sub/A=参数即可:

E:\OpenSource\GitHub\RainbowMango\GoExpertProgrammingSourceCode\GoExpert\src\gotest>go test subunit_test.go -v -run Sub/A=
=== RUN   TestSub
=== RUN   TestSub/A=1
=== RUN   TestSub/A=2
--- PASS: TestSub (0.00s)
    --- PASS: TestSub/A=1 (0.00s)
    --- PASS: TestSub/A=2 (0.00s)
PASS
ok      command-line-arguments  0.340s

上例中,使用参数-run Sub/A=则只会执行TestSub/A=1TestSub/A=2两个子测试。

对于子性能测试则使用-bench参数来筛选,此处不再赘述。

注意:此处的筛选不是严格的正则匹配,而是包含匹配。比如,-run A=那么所有测试(含子测试)的名字中如果包含“A=”则会被选中执行。

子测试并发

前面提到的多个子测试共享setup和teardown有一个前提是子测试没有并发,如果子测试使用t.Parallel()指定并发,那么就没办法共享teardown了,因为执行顺序很可能是setup->子测试1->teardown->子测试2...。

如果子测试可能并发,则可以把子测试通过Run()再嵌套一层,Run()可以保证其下的所有子测试执行结束后再返回。

为便于说明,我们创建文件subparallel_test.go用于说明:

package gotest_test

import (
    "testing"
    "time"
)

// 并发子测试,无实际测试工作,仅用于演示
func parallelTest1(t *testing.T) {
    t.Parallel()
    time.Sleep(3 * time.Second)
    // do some testing
}

// 并发子测试,无实际测试工作,仅用于演示
func parallelTest2(t *testing.T) {
    t.Parallel()
    time.Sleep(2 * time.Second)
    // do some testing
}

// 并发子测试,无实际测试工作,仅用于演示
func parallelTest3(t *testing.T) {
    t.Parallel()
    time.Sleep(1 * time.Second)
    // do some testing
}

// TestSubParallel 通过把多个子测试放到一个组中并发执行,同时多个子测试可以共享setup和tear-down
func TestSubParallel(t *testing.T) {
    // setup
    t.Logf("Setup")

    t.Run("group", func(t *testing.T) {
        t.Run("Test1", parallelTest1)
        t.Run("Test2", parallelTest2)
        t.Run("Test3", parallelTest3)
    })

    // tear down
    t.Logf("teardown")
}

上面三个子测试中分别sleep了3s、2s、1s用于观察并发执行顺序。通过Run()将多个子测试“封装”到一个组中,可以保证所有子测试全部执行结束后再执行tear-down。

命令行下的输出如下:

E:\OpenSource\GitHub\RainbowMango\GoExpertProgrammingSourceCode\GoExpert\src\gotest>go test subparallel_test.go -v -run SubParallel
=== RUN   TestSubParallel
=== RUN   TestSubParallel/group
=== RUN   TestSubParallel/group/Test1
=== RUN   TestSubParallel/group/Test2
=== RUN   TestSubParallel/group/Test3
--- PASS: TestSubParallel (3.01s)
        subparallel_test.go:25: Setup
    --- PASS: TestSubParallel/group (0.00s)
        --- PASS: TestSubParallel/group/Test3 (1.00s)
        --- PASS: TestSubParallel/group/Test2 (2.01s)
        --- PASS: TestSubParallel/group/Test1 (3.01s)
        subparallel_test.go:34: teardown
PASS
ok      command-line-arguments  3.353s

通过该输出可以看出:

  1. 子测试是并发执行的(Test1最先被执行却最后结束)
  2. tear-down在所有子测试结束后才执行

总结

  • 子测试适用于单元测试和性能测试;
  • 子测试可以控制并发;
  • 子测试提供一种类似table-driven风格的测试;
  • 子测试可以共享setup和tear-down;

© 著作权归作者所有

共有 人打赏支持
恋恋美食

恋恋美食

粉丝 91
博文 105
码字总数 98017
作品 0
杭州
高级程序员
私信 提问
MySQL数据库获取汉字拼音的首字母函数

需求简介:最 近的一个项目,想实现如下图所示的显示效果。很明显,如果能够获取对应的汉字词组的拼音首字母就可以实现了,如果是固定的几个汉字,人为的拼一下就可以 了,不过项目中有多处功...

豆花饭烧土豆
2016/03/13
44
0
Enterprise Architect学习笔记-EA中关系

Enterprise Architect中定义的关系主要有一下几种: ●Associate(关联):类之间有关联,通常是作为变量存在; ●Aggregate(聚合):类A包含类B或由类B组成; ●Compose(组合):类A是由其他...

毛朱
2013/03/25
0
0
【渗透攻防】深入了解Windows

第一节 初识Windows 1.1 什么是Windows Microsoft Windows,是美国微软公司研发的一套操作系统,它问世于1985年,起初仅仅是Microsoft-DOS模拟环境,后续的系统版本由于微软不断的更新升级,不...

i春秋学院
2016/08/03
364
3
关于 fir.im 你可能不知道的实用小工具

大家可能都知道 fir.im 是做测试发包的,上传你的 IPA/APK, 测试用户可以通过一个短链接和二维码就可快速安装测试。 除了基本的发包功能即应用上传下载外,fir.im 还为提高发包体验提供了一系...

风起云飞fir_im
2015/11/16
0
0
Unity 手游自动化测试框架--GAutomator

GAutomator GAutomator是一个针对Unity手游的UI自动化测试框架。设计理念与使用方式,类似于Android的UIAutomator。GAutomator以Unity中的GameObject为操作对象,通过操作GameObject实现UI自动...

匿名
2016/12/06
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

Android Studio Unable to resolve dependency for错误的排查

记录一次Android Studio Unable to resolve dependency for错误的排查 Android Studio 3.2.1 错误提示 Unable to resolve dependency for... 原因:在gradle中设置的代理并没有gradle 4.6的版......

Gemini-Lin
7分钟前
0
0
java常用设计模式

设计模式; 一个程序员对设计模式的理解: “不懂”为什么要把很简单的东西搞得那么复杂。后来随着软件开发经验的增加才开始明白我所看到的“复杂”恰恰就是设计模式的精髓所在,我所理解的“...

呵呵哒灬
40分钟前
3
0
Kafka入门

1、Kafka使用背景 在我们大量使用分布式数据库、分布式计算集群的时候,是否会遇到这样的一些问题: 我们想分析下用户行为(pageviews),以便我们设计出更好的广告位 我想对用户的搜索关键词...

watermelon11
昨天
0
0
Cannot list resources Permission denied: user=Administrator, access=READ_EXECUTE, inode="/tmp"

Cannot list resources Permission denied: user=ÁõÎĺÁ, access=READ_EXECUTE, inode="/tmp":root:supergroup:drwx-wx-wx windows系统 Spring boot 整合hadoop时报错。 java.lang.Ille......

lwenhao
昨天
2
0
【结构型】- 享元模式

享元模式 作用:利用共享技术有效地支持大量细粒度对象的复用 享元模式状态 内部状态:在享元对象内部不随外界环境改变而改变的共享部分,存储于享元对象内部 外部状态:随着环境的改变而改变...

ZeroneLove
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部