Go-知识测试-子测试
Go-知识测试-子测试
- 1. 介绍
- 2. 例子
- 3. 子测试命名规则
- 4. 选择性执行
- 5. 子测试并发
- 6. testing.T.Run
- 7. testing.T.Parallel
- 8. 子测试适用于单元测试
- 9. 子测试适用于性能测试
- 10. 总结
- 10.1 启动子测试 Run
- 10.2 启动并发测试 Parallel
建议先看:https://blog.csdn.net/a18792721831/article/details/140062769
Go-知识测试-工作机制
1. 介绍
子测试提供了一种在一个测试函数中执行多个测试的能力,可以自己编排执行顺序,或者做一些初始化等操作。
2. 例子
比如如下代码:
import "testing"func SubA(t *testing.T) {t.Log("test A " + t.Name())
}func SubB(t *testing.T) {t.Log("test B " + t.Name())
}func SubC(t *testing.T) {t.Log("test C " + t.Name())
}func TestSub(t *testing.T) {t.Run("name=A", SubA)t.Run("name=B", SubB)t.Run("name=C", SubC)
}
使用go test -v xx_test.go执行

3. 子测试命名规则
Run()方法的第一个参数作为子测试的名字,这里只是本层级的名字。
实际上子测试的内部命名规则是: <父测试名字>/<传递给Run的名字>
比如我们在B里面在调用A:

执行后:

name具有传递性
4. 选择性执行
在上面我们有 name=A,name=B,name=C 三个测试,如果只是想执行A呢
使用go test -v xx_test.go -run TestSub/name=A

选择性执行的字符串,是包含匹配,不是严格的正则匹配。

5. 子测试并发
可以看到,前面的子测试都是根据代码顺序执行,串行执行,并没有并发。
使用 t.Parallel 可以让当前测试函数允许并发。
比如如下例子不加并发的时候:
import ("testing""time"
)func SubA(t *testing.T) {t.Log("test A " + t.Name())time.Sleep(time.Second*3)
}func SubB(t *testing.T) {t.Log("test B " + t.Name())time.Sleep(time.Second*2)
}func SubC(t *testing.T) {time.Sleep(time.Second*1)t.Log("test C " + t.Name())
}func TestSub(t *testing.T) {t.Run("name=A", SubA)t.Run("name=B", SubB)t.Run("name=C", SubC)
}
执行后用时超过6秒

允许并发:
import ("testing""time"
)func SubA(t *testing.T) {t.Parallel()t.Log("test A " + t.Name())time.Sleep(time.Second * 3)
}func SubB(t *testing.T) {t.Parallel()t.Log("test B " + t.Name())time.Sleep(time.Second * 2)
}func SubC(t *testing.T) {t.Parallel()time.Sleep(time.Second * 1)t.Log("test C " + t.Name())
}func TestSub(t *testing.T) {t.Run("name=A", SubA)t.Run("name=B", SubB)t.Run("name=C", SubC)
}

A最先被调度,但是确是最后执行完毕。
需要注意的是,当开启子测试并发后,调用了子测试后,父测试的代码和子测试代码执行顺序就是随机的了。
所以如果在主测试中需要做一些初始化,然后在执行子测试,那么需要注意,有可能初始化还未完成,子测试已经开始执行了。
6. testing.T.Run
// 将运行f作为名为name的t的子测试。它在一个单独的goroutine中运行f
// 并且阻塞直到f返回或调用t。并行成为并行测试。
// 运行报告f是否成功(或者至少在调用t.Parallel之前没有失败)。
//
// Run可以从多个goroutine同时调用,但所有此类调用
// 必须在t的外部测试函数返回之前返回。
func (t *T) Run(name string, f func(t *T)) bool {atomic.StoreInt32(&t.hasSub, 1)testName, ok, _ := t.context.match.fullName(&t.common, name)if !ok || shouldFailFast() {return true}//记录此调用点的堆栈跟踪,以便如果子测试//在单独的堆栈中运行的函数被标记为助手,我们可以//继续将堆栈遍历到父测试中。var pc [maxStackLen]uintptrn := runtime.Callers(2, pc[:])t = &T{common: common{barrier: make(chan bool),signal: make(chan bool, 1),name: testName,parent: &t.common,level: t.level + 1,creator: pc[:n],chatty: t.chatty,},context: t.context,}t.w = indenter{&t.common}if t.chatty != nil {t.chatty.Updatef(t.name, "=== RUN %s\n", t.name)}//而不是在调用之前减少此测试的运行计数//tRunner并在之后增加它,我们依靠tRunner保持//计数正确。这样可以确保运行一系列顺序测试//而不会被抢占,即使它们的父级是并行测试。这//如果*parallel==1,则可以特别减少意外。go tRunner(t, f)if !<-t.signal {//此时,FailNow很可能是在//其中一个子测验的家长测验。继续中止链的上行。runtime.Goexit()}return !t.failed
}
在testing.Run中,会创建一个testing.T对象,然后将调用者作为parent,然后调用testing.tRunner执行。
同时会设置父测试有子测试的标志:hasSub。
一个树形结构,父测试不知道有哪些子测试,但是父测试知道需要等待子测试执行完成。
7. testing.T.Parallel
// 与此测试并行运行的并行信号(且仅与)
// 其他平行测试。当测试由于使用而多次运行时
// -test.count或-test.cpu,单个测试的多个实例从未在中运行
// 彼此平行。
func (t *T) Parallel() {if t.isParallel {panic("testing: t.Parallel called multiple times")}if t.isEnvSet {panic("testing: t.Parallel called after t.Setenv; cannot set environment variables in parallel tests")}t.isParallel = trueif t.parent.barrier == nil {// T.Parallel has no effect when fuzzing.// Multiple processes may run in parallel, but only one input can run at a// time per process so we can attribute crashes to specific inputs.return}//我们不想把等待串行测试的时间包括在内//在测试持续时间内。记录到目前为止经过的时间,并重置//计时器之后。t.duration += time.Since(t.start)//添加到要由父级发布的测试列表中。t.parent.sub = append(t.parent.sub, t)t.raceErrors += race.Errors()if t.chatty != nil {//不幸的是,即使PAUSE表示命名测试是*no//运行时间较长*,cmd/test2json将其解释为更改活动测试//用于日志解析。我们可以修复cmd/test2json,但是//不会修复已经shell的第三方工具的现有部署//向外扩展到cmd/test2json的旧版本——因此仅修复cmd/test1json//目前还不够。t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)}t.signal <- true // Release calling test.<-t.parent.barrier // Wait for the parent test to complete.t.context.waitParallel()if t.chatty != nil {t.chatty.Updatef(t.name, "=== CONT %s\n", t.name)}t.start = time.Now()t.raceErrors += -race.Errors()
}
设置当前testing.T的并发状态为true,因为Parallel在子测试中调用的,因此testing.T是子测试的T。
testing.Run是在父测试中调用的,因此testing.T是父测试。
将当前子测试加入到父测试的sub列表中,由父测试启动。
8. 子测试适用于单元测试
在testing.common中,hasSub表示是否有子测试,sub 则是子测试列表(testing.T)

在testing.tRunner中,有对子测试相关的支持

if len(t.sub) > 0 表示,如果有子测试,那么触发子测试执行,并且等待子测试执行完成。
else if t.isParallel 表示,如果是允许并发的,那么释放锁。
testing.tRunner 不管是父测试,还是子测试,都会执行。
9. 子测试适用于性能测试
在testing.B.Run中,设置父测试的hasSub标志为1。

并且创建一个testing.B,通过先调用testing.B.run1在调用testing.B.run执行。
并且子测试的数据会附加到父测试的报告中。
10. 总结
10.1 启动子测试 Run
Run 函数启动一个单独的协程来运行名字为name的子测试f,并且会阻塞等待其执行结束,除非子测试f显式调用Parallel将自己编程一个可并行的测试,最后返回bool类型的测试结果。
所有的测试,都是由TestMain使用Run方法直接或者间接启动。
每启动一个子测试,都会创建一个testing.T或者testing.B变量,该变量集成当前测试的部分属性,然后以新的
协程执行,当前测试会在子测试结束后返回子测试的结果。
子测试退出条件要么是子测试执行结束,要么是子测试设置了Parallel,否则是异常退出。
10.2 启动并发测试 Parallel
Parallel方法将当前测试加入并发队列。
启动并发测试,在排队等待过程中,消耗的时间不能统计到测试的耗时内,所以在测试真正被并发调度后,清空等待时间。
相关文章:
Go-知识测试-子测试
Go-知识测试-子测试 1. 介绍2. 例子3. 子测试命名规则4. 选择性执行5. 子测试并发6. testing.T.Run7. testing.T.Parallel8. 子测试适用于单元测试9. 子测试适用于性能测试10. 总结10.1 启动子测试 Run10.2 启动并发测试 Parallel 建议先看:https://blog.csdn.net/a…...
.net core IConfiguration 读 appsettings.json 数据,举例
在.NET Core中,IConfiguration 接口是用来读取配置数据的,包括从 appsettings.json 文件中读取。下面是一个如何在使用.NET Core时通过 IConfiguration 读取 appsettings.json 数据的示例。 首先,假设你的 appsettings.json 文件内容如下&am…...
全球Windows机器蓝屏,作为量化人,我的检讨来了
昨天下午,微软给大家放了个假。Windows又双叒死机了。不过,这一次不是几台机器,而是全球大范围宕机。这一刻,大家都是“正蓝旗”。 蓝瓶的,效果好! 现在根本原因已经找到,绝大多数人的机器都已修…...
部署和运维
目录 1.Git1.1. Git指令中merge和rebase的区别1. Commit 记录2. 合并方式3. 冲突处理4. 使用场景选择建议 1.2. cherry-pick的使用如何使用 git cherry-pick例子处理冲突撤销 cherry-pick其他选项 结论 2. 部署1. Nginx的使用场景 编译打包1. webpack2. webpack打包优化1. 代码…...
微信小程序基本语法
官网 https://developers.weixin.qq.com/miniprogram/dev/framework/ 视频教程:尚硅谷微信小程序开发教程,2024最新微信小程序项目实战! 仿慕尚花坊项目源码:https://gitee.com/abcdfdewrw/flower-workshop 目录 一,初…...
测试用例的设计方法
等价类 等价类概念:在所有测试的数据中,具有某种共同特征的数据子集 边界值 边界值分析是对程序输入或输出的边界值进行测试的一种黑盒测试方法 边界值是作为等价类的补充,其主要区别是: 边界值测试设计不是从某一个等价类中…...
Android10.0 锁屏分析-KeyguardPatternView图案锁分析
首先一起看看下面这张图: 通过前面锁屏加载流程可以知道在KeyguardSecurityContainer中使用getSecurityView()根据不同的securityMode inflate出来,并添加到界面上的。 我们知道,Pattern锁所使用的layout是 R.layout.keyguard_pattern_view&a…...
Python 装饰器:函数的函数,代码的艺术
引言 在Python中,装饰器是一种强大的功能,允许程序员在不修改原函数源码的情况下增强或修改函数行为。装饰器本质上是一个接收函数作为参数的高阶函数,并返回一个新的函数或修改原函数的行为。这种机制极大地提高了代码的复用性、可读性和模…...
安全防御2
实验要求: 实验过程: 7,办公区设备可以通过电信链路和移动链路上网(多对多的NAT,并且需要保留一个公网IP不能用来转换): 新建电信区: 新建移动区: 将对应接口划归到各自区域: 新建…...
C语言 ——— 打印水仙花数
目录 何为水仙花数 题目要求 代码实现 何为水仙花数 “水仙花数”是指一个n位数,其各位数字的n次方之和等于该数本身 如:153 1^3 5^3 3^3,则153就是一个“水仙花数” 题目要求 求出0~100000的所有“水仙花数”并输出 代码实现 #i…...
「Conda」在Linux系统中安装Conda环境管理器
在Linux系统中安装Conda环境管理器是一个相对简单的过程。 1. 准备工作 确保你的Linux系统已经更新到最新版本,并安装了基本的开发工具和库。打开终端,执行以下命令: sudo apt-get update sudo apt-get upgrade sudo apt-get install build-essential2. 安装Miniconda或An…...
9.11和9.9哪个大?GPT-4o也翻车了
今天刷到了这个问题,心血来潮去问下chatgpt-4o,没想到疯狂翻车... 第一次问: GPT一开始给出了难绷的解答,让我想起了某短视频软件评论区里对某歌手节目排名的质疑哈哈哈哈哈 但是在接下来的进一步询问和回答中它反应过来了。 第…...
[开源]语雀+Vercel:打造免费个人博客网站
大家好,我是白露。 今天我想和大家分享我的今年的第一个开源项目 —— 基于语雀+Nextjs+Vercel实现免费的博客系统。 简单来说,你在语雀写博客,然后直接一键同步到个人网站上,网站自动部署! 而且,整个过程几乎不需要额外的成本,也不用充值语雀超级会员,hh。这个项目…...
使用ElementUI和element-china-area-data库实现省市区三级联动组件封装
在前端开发中,省市区三级联动是一个常见的需求。今天我们将使用Vue.js和ElementUI组件库,结合element-china-area-data库,来实现一个省市区三级联动的组件。这个组件不仅可以提高用户体验,还能大大简化我们的代码。接下来…...
0718,TCP协议,三次握手,四次挥手
目录 上课喵: TCP(Transmission Control Protocol,传输控制协议)的状态迁移图 TCP连接的状态迁移图 状态迁移说明: 注意: big_htonl.c 字节序转换 addr.c IP地址的转换 作业喵: …...
如何安装Visual Studio Code
Visual Studio Code(简称 VS Code) Visual Studio Code 是一款由微软开发的免费、开源的现代化轻量级代码编辑器。 主要特点包括: 跨平台:支持 Windows、Mac 和 Linux 等主流操作系统,方便开发者在不同平台上保持一…...
vi 编辑器快捷生成 main 函数和基本框架
step1: 执行 sudo vi /etc/vim/vimrc (修改vimrc需要管理员权限:sudo) step2:输入用户密码,回车, 编辑vimrc文件 step3:在尾行输入以下代码(可复制) map mf i#include<stdio.h><ESC>o#includ…...
npm相关指令
切换镜像 腾讯镜像 npm config set registry https://mirrors.cloud.tencent.com/npm/ 淘宝镜像(新版) npm config set registry https://registry.npmmirror.com 淘宝镜像(旧版,已弃用) npm config set regist…...
为什么不要碰自媒体
要是失业了,搞自媒体,可行吗?毫无希望! 如今的自媒体早卷得不成样子了,很难再有机会,根本原因在于几乎没有增量用户的同时,存量用户也不再有剩余时间,全量用户的时间早已被几个自媒…...
酷炫末世意境背景404单页HTML源码
源码介绍 酷炫末世意境背景404单页HTML源码,背景充满着破坏一切的意境,彷佛末世的到来,可以做网站错误页或者丢失页面,将下面的代码放到空白的HTML里面,然后上传到服务器里面,设置好重定向即可 效果预览 …...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...
