简介

简单的说,子测试提供一种在一个测试函数中执行多个测试的能力,比如原来有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 可以打印交互信息

D:\gopath\src\Go_base\lesson\test_demo\gotest>go test -v sub_test.go gotest.go
=== 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.045s

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

子测试命名规则

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

过滤筛选

通过测试的名字,可以在执行中过滤掉一部分测试。 比如,只执行上例中A=*的子测试,那么执行时使用-run Sub/A=参数即可

D:\gopath\src\Go_base\lesson\test_demo\gotest>go test -v sub_test.go gotest.go -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.074s

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

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

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

子测试并发

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

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

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

package gotest_test

import (
"fmt"
"testing"
"time"
) // 并发子测试,无实际测试工作,仅用于演示
func parallelTest1(t *testing.T) {
t.Parallel()
time.Sleep(3 * time.Second)
fmt.Println("parallel test 1")
} // 并发子测试,无实际测试工作,仅用于演示
func parallelTest2(t *testing.T) {
t.Parallel()
time.Sleep(2 * time.Second)
fmt.Println("parallel test 2")
} // 并发子测试,无实际测试工作,仅用于演示
func parallelTest3(t *testing.T) {
t.Parallel()
time.Sleep(1 * time.Second)
fmt.Println("parallel test 3")
} // 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。

输出如下:

D:\gopath\src\Go_base\lesson\test_demo\gotest>go test -v subparallel_test.go
=== RUN TestSubParallel
subparallel_test.go:33: Setup
=== RUN TestSubParallel/group
=== RUN TestSubParallel/group/Test1
=== PAUSE TestSubParallel/group/Test1
=== RUN TestSubParallel/group/Test2
=== PAUSE TestSubParallel/group/Test2
=== RUN TestSubParallel/group/Test3
=== PAUSE TestSubParallel/group/Test3
=== CONT TestSubParallel/group/Test1
=== CONT TestSubParallel/group/Test2
=== CONT TestSubParallel/group/Test3
parallel test 3
parallel test 2
parallel test 1
=== CONT TestSubParallel
subparallel_test.go:42: teardown
--- PASS: TestSubParallel (3.01s)
--- PASS: TestSubParallel/group (0.00s)
--- PASS: TestSubParallel/group/Test3 (1.01s)
--- PASS: TestSubParallel/group/Test2 (2.01s)
--- PASS: TestSubParallel/group/Test1 (3.01s)
PASS
ok command-line-arguments 3.050s

通过该输出可以看出:

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

总结

  1. 总测试适用于单元测试和性能测试
  2. 子测试可以控制并发
  3. 子测试提供一种类似table-driven(表格驱动测试)风格的测试
  4. 子测试可以共享setup 和 tear-down;

Go测试--子测试的更多相关文章

  1. Go测试--main测试

    目录 简介 示例 简介 子测试的一个方便之处在于可以让多个测试共享Setup和Tear-down.但这种程度的共享有时并不满足需求,有时希望在整个测试程序做一些全局的setup和Tear-down,这 ...

  2. APP敏捷测试,测试和开发并行!

    测试和开发具有同等重要的作用,从一开始,测试和开发就是相向而行的.测试是开发团队的一支独立的.重要的支柱力量. 测试要具备独立性,独立分析业务需求,独立配置测试环境,独立编写测试脚本,独立开发测试工具 ...

  3. 软件测试 -- 和用户共同测试(UAT测试)的注意点有哪些

    软件产品在投产前,通常都会进行用户验收测试.如果用户验收测试没有通过,直接结果就是那不到“Money”,间接影响是损害了公司的形象,而后者的影响往往更严重.根据作者的经验,用户验收测试一定要让用户满意 ...

  4. 衣联网络-亿能测试 安全测试沙龙 PPT资料免费下载

    衣联网络-亿能测试 安全测试沙龙 PPT资料免费下载http://automationqa.com/forum.php?mod=viewthread&tid=2304&fromuid= ...

  5. 冒烟测试、α测试、Beta测试、性能测试

    “冒烟测试”(也可称为showcase)这一术语描述的是在将代码更改嵌入到产品的源树中之前对这些更改进行验证的过程. 冒烟测试(smoke test)在测试中发现问题,找到了一个Bug,然后开发人员会 ...

  6. Apache JMeter开源压力测试/负载测试工具 2.12 官方最新版

    软件介绍   Jmeter是一款使用Java开发的,开源免费的,测试工具, 主要用来做功能测试和性能测试(压力测试/负载测试),而且用Jmeter 来测试 Restful API, 非常好用. 如何学 ...

  7. JUit——(三)JUnit核心对象(测试、测试类、Suit和Runner)

    JUnit的核心对象:测试.测试类.测试集(Suite).测试运行器 1. 测试: @Test注释的.公共的.不带有任何参数.并且返回void类型的方法 2. 测试类: 公共的,包含对应类的测试方法的 ...

  8. app测试--稳定性测试

    稳定性测试的概念有2种, 一, 稳定性测试,对应于异常性测试,即发生异常情况时,系统如何反应的测试.包含: 1 交互性测试,被打扰的情况,如来电,短信,低电量等.这些其实在上章的功能测试中有提到. 2 ...

  9. Net Manager测试连接测试没有成功,用户权限问题,以管理员身份运行后测试成功

    Net Manager测试连接测试没有成功,截图如下:

随机推荐

  1. 如何在cmd中运行.py文件

    C:\Users\mf>cd C:\Program Files\Python36\ C:\Program Files\Python36>python const.py 切换到.py文件所在 ...

  2. C++第三十五篇 -- 写第一个驱动开发程序

    VS2017+WDK+VMware12+Win10环境配置完毕,接下来写第一个驱动程序. 1.新建一个KMDF的程序. 2.配置项目属性. 3.编译项目.一般这里应该成功,我一台电脑成功了,另一台电脑 ...

  3. redis故障时的一些概念

    1.缓存穿透 概念访问一个不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉. 解决方案采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤 ...

  4. Skywalking-04:扩展Metric监控信息

    扩展 Metric 监控信息 官方文档 Source and Scope extension for new metrics 案例:JVM Thread 增加 Metrics 修改 Thread 的定 ...

  5. (opencv01)读入图像

    (opencv01)Opencv之读入图像 读入图像  img = cv2.imread(filepath, flags) filepath : 要读入图片的完整路径 flags : 读入图片的标志 ...

  6. 论文笔记:(2019CVPR)PointConv: Deep Convolutional Networks on 3D Point Clouds

    目录 摘要 一.前言 1.1直接获取3D数据的传感器 1.2为什么用3D数据 1.3目前遇到的困难 1.4现有的解决方法及存在的问题 二.本文idea 2.1 idea来源 2.2 初始思路 2.3 ...

  7. 外网远程顶级域名连接群晖的WebDAV文件服务映射盘符

       外网远程顶级域名连接群晖的WebDAV文件服务映射盘符 https://www.cnblogs.com/delphixx/p/11846546.html 电子文件管理规范   1.手机拍照截屏 ...

  8. 大数据开发-Go-数组,切片

    new()和make的区别 二者看起来没什么区别,但是他们的行为不同,分别适用于不同的类型 new (T) 为每个新的类型 T 分配一片内存,初始化为 0 并且返回类型为 * T 的内存地址:这种方法 ...

  9. Vue 脚手架学习

    首先就是安装脚手架 npm install @vue/cil -g 全局安装 在这里我遇到一个问题:安装不了脚手架,报错显示: 通过苦逼的查找原因就是 以前使用的taobao镜像 导致的,删除镜像换成 ...

  10. 我快被Framework源码烦死了!

    前言 这段时间,忙到没时间学新东西,都有点心有余而力不足,想着抽空补补课,于是重读了Framework源码. 因为Framework源码太重要了,像掉帧监控.函数插装.慢函数检测.ANR 监控.启动监 ...