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]uintptr
	n := 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 = true
	if 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方法将当前测试加入并发队列。
启动并发测试,在排队等待过程中,消耗的时间不能统计到测试的耗时内,所以在测试真正被并发调度后,清空等待时间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/797008.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探索“搭旅万物皆可搭”小程序——构建旅行搭伴平台的创新实践

摘要 随着旅游市场的不断发展和个性化需求的日益增长&#xff0c;旅行搭伴平台逐渐成为连接志同道合旅者的桥梁。本文旨在介绍“搭旅万物皆可搭”小程序的设计理念、核心功能及其背后的技术实现&#xff0c;探讨如何通过算法优化、安全保障、社交互动等手段&#xff0c;打造一…

手撕Vue中的RouterLink和RouterView,深入理解其底层原理(一)

RouterLink和RouterView的作用 我们可以通过RouterLink绑定好指向的路径 点击就能够实现在RouterView中将页面显示出来 我们首先使用官方的vue-router展示一下效果 App.vue <template><div><router-link to"/">Home</router-link><ro…

51单片机STC89C52RC——17.2 红外遥控数字加减、电机调速

目的/效果 1&#xff1a;按VOL-键数字减、按VOL加数字加 2&#xff1a;按键 0&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;4 电机调速 一&#xff0c;STC单片机模块 二&#xff0c;红外遥控 详细了解红外遥控控制原理请参考《51单片机STC89C52RC——17.1 红外线遥控…

UE4 解决创建布料报错:三角形退化

**【问题】**创建创建布料时报错&#xff1a;三角形退化 【方法】 1.要重新绑定&#xff1a;导入到ue4为静态网格体&#xff0c;勾选“移除退化”&#xff0c;再导出fbx&#xff0c;再重新绑定 2.不用重新绑定&#xff1a;使用排除法&#xff08;费时&#xff09;&#xff0c…

Spring Boot快速上手

一&#xff0c;什么是spring 首先登陆Spring官网&#xff0c;看一下官网如何形容的&#xff0c; 可以看出Spring是为了使java程序更加快速&#xff0c;方便&#xff0c;安全所做出的java框架。 1.Spring Boot Spring Boot的诞生就是为了简化Spring的开发&#xff0c;也就是更…

【Quart 框架——来源于Flask的强大且灵活的异步Web框架】

目录 前言一、Quart简介1-1、简介1-2、与flask的区别 二、快速开始2-1、安装2-2、基本用法 三、核心功能3-1、异步路由3-2、WebSockets 支持3-3、中间件3-4、蓝图 (Blueprints) 四、部署4-1、使用uvicorn部署4-2、使用hypercorn部署 五、案例分析总结 前言 Quart 是一个基于 Py…

taocms 3.0.1 本地文件泄露漏洞(CVE-2021-44983)

前言 CVE-2021-44983 是一个影响 taoCMS 3.0.1 的远程代码执行&#xff08;RCE&#xff09;漏洞。该漏洞允许攻击者通过上传恶意文件并在服务器上执行任意代码来利用这一安全缺陷。 漏洞描述 taoCMS 是一个内容管理系统&#xff08;CMS&#xff09;&#xff0c;用于创建和管…

用Qwt进行图表和数据可视化开发

目录 Qwt介绍 示例应用场景 典型QWT开发流程 举一些Qwt的例子&#xff0c;多绘制几种类型的图像 1. 绘制折线图 (Line Plot) 2. 绘制散点图 (Scatter Plot) 3. 绘制柱状图 (Bar Plot) 4. 绘制直方图 (Histogram) Qwt介绍 QWT开发主要涉及使用QWT库进行图表和数据可视化…

在若依框架基础上开发新功能

本文介绍如何在若依框架&#xff08;不分离版本&#xff09;的基础上开发新功能。 目录 运行若依框架 下载若依框架代码 IDEA打开若依框架代码 初始化数据库 修改数据库配置 运行项目 设计数据库 数据表命名规则 建表及初始化数据 开发新功能 后端CRUD功能 用户前端…

从零开始做题:神奇的棋盘

题目 打开得到一副adfgvx加密棋盘 观察txt数据只有1-5&#xff0c;猜测是数字字母坐标转换&#xff0c;用notepad批量操作一下 解题 AGAXXDAGGVGGVDVADAVXDGADVGDVAADDDDFXAFAFDGDVXXDGGDGGDXDDFDDXVGXADGVDFXVVAADDXDXXADDVGGGXGXXXXGXXGGXGDVVVGGGAGAAAAGAAGGAGDDDAGAGGG…

JS实现:统计字符出现频率/计算文字在文本中的出现次数

要实现这个功能&#xff0c;JavaScript 一个非常强大的方法&#xff0c;那就是reduce() reduce() 它用于将数组的所有元素减少到一个单一的值。这个值可以是任何类型&#xff0c;包括但不限于数字、字符串、对象或数组。 reduce() 方法接收一个回调函数作为参数&#xff0c;这个…

Java单边表的局部翻转

反转链表 II 这是上一个翻转全部链表的进阶版&#xff0c;大家可以先去看我的上一篇博客 Java算法之单链表的全部翻转-CSDN博客 题目描述 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节…

Spring Cloud Eureka

引入&#xff1a;远程调用时&#xff0c;url是写死的 String url "http://127.0.0.1:9090/product/" orderInfo.getProductId(); 解决思路&#xff1a; 比如&#xff08;医院&#xff0c;学校等&#xff09;机构的电话号码发生变化&#xff0c;就需要通知各个使⽤…

mybatilsplaus 常用注解

官网地址 baomidou注解配置

vue3项目,表单增删改

效果图 ArticleChannel.vue页面代码 <script setup> import {artGetChannelsService ,artDelChannelService} from /api/article.js import { Edit, Delete } from element-plus/icons-vue //调用open方法&#xff0c;ChannelEdit去修改组件内部类容 import ChannelEdit…

【Linux】1w详解如何实现一个简单的shell

目录 实现思路 1. 交互 获取命令行 2. 子串分割 解析命令行 3. 指令的判断 内建命令 4. 普通命令的执行 补充&#xff1a;vim 文本替换 整体代码 重点思考 1.getenv和putenv是什么意思 2.代码extern char **environ; 3.内建命令是什么 4.lastcode WEXITSTATUS(sta…

linux nethogs网络监控程序(端口监控、流量监控、上传流量、下载流量、进程监控进程网络)

文章目录 Nethogs 网络监控程序详解1. 引言2. Nethogs 的安装与运行2.1 安装 Nethogs- **Debian/Ubuntu**- **Fedora**- **Arch Linux** 2.2 运行 Nethogs 3. Nethogs 的使用详解3.1 基本界面- **PID**&#xff1a;进程的 ID。- **用户**&#xff1a;运行该进程的用户。- **程序…

graphviz subgraph添加边界框

subgraph name 属性必须要以cluster开头。 A Quick Introduction to GraphvizAn awesome tool for software documentation and visualizing graphshttps://www.worthe-it.co.za/blog/2017-09-19-quick-introduction-to-graphviz.html digraph {rankdir"LR"// the n…

DEBUG:jeston卡 远程ssh编程

问题 jeston 打开网页 gpt都不方便 而且只需要敲命令就行 解决 下载MobaXterm(window执行) liunx需要虚拟机 软件 远程快速复制命令

7.13 专题训练DP

P1255 数楼梯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) ac代码 #include<bits/stdc.h> using namespace std; typedef long long ll; #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) const ll mod 1e97;int main() {IOS;int n;cin>>n;int a[…