Go 表驱动测试实战:用 t.Run 子测试组织可维护的单元测试
Go 表驱动测试实战:用 t.Run 子测试组织可维护的单元测试你给一个函数写单测,第一版是复制粘贴:测输入 A 断言一段,测输入 B 再抄一遍断言,测边界值又抄一遍。三个用例还好,等长到十几个,某天函数签名改了,你得挨个改十几段几乎一样的代码。更糟的是,一个断言t.Fatal挂掉,后面的用例根本没跑,你不知道到底错了几个。Go 社区的标准答案是表驱动测试:把用例做成一张表,循环跑,配合t.Run拆成独立子测试。这篇手把手带你从「复制粘贴」重构到「一张表搞定」。被测函数拿一个简单的场景:把秒数格式化成人类可读的时长。packagetimeutilimportfmt// FormatDuration 把秒数格式化成 1h2m3s 这样的字符串funcFormatDuration(secint)(string,error){ifsec0{return,fmt.Errorf(秒数不能为负: %d,sec)}h,m,s:sec/3600,(sec%3600)/60,sec%60returnfmt.Sprintf(%dh%dm%ds,h,m,s),nil}朴素写法:复制粘贴,又臭又长第一版新手写法,每个用例抄一遍:funcTestFormatDuration_Naive(t*testing.T){got,_:FormatDuration(0)ifgot!0h0m0s{t.Fatalf(0 秒: 期望 0h0m0s, 得到 %s,got)}got,_FormatDuration(3661)ifgot!1h1m1s{t.Fatalf(3661 秒: 期望 1h1m1s, 得到 %s,got)}_,err:FormatDuration(-1)iferrnil{t.Fatal(负数应该报错)}}三个问题:断言逻辑重复三遍;t.Fatalf一旦触发,后面的用例直接不跑了;加用例只能继续往下抄。表驱动重构:用例是数据,断言只写一次核心思路是把「输入 期望输出」抽成一个结构体切片(就是那张「表」),断言逻辑写一遍,循环套用:funcTestFormatDuration(t*testing.T){// 这张表就是全部用例,加用例 加一行tests:[]struct{namestring// 用例名,出错时能一眼看出是哪个inputintwantstringwantErrbool}{{name:零秒,input:0,want:0h0m0s,wantErr:false},{name:一分钟,input:60,want:0h1m0s,wantErr:false},{name:时分秒齐全,input:3661,want:1h1m1s,wantErr:false},{name:负数报错,input:-1,want:,wantErr:true},}for_,tt:rangetests{got,err:FormatDuration(tt.input)if(err!nil)!tt.wantErr{t.Errorf(%s: 是否报错 %v, 期望 wantErr %v,tt.name,err!nil,tt.wantErr)continue}ifgot!tt.want{t.Errorf(%s: 得到 %q, 期望 %q,tt.name,got,tt.want)}}}注意这里用t.Errorf而不是t.Fatalf——Errorf标记失败但继续跑,所以一次能看到所有失败的用例,而不是碰到第一个就停。加新用例只需在表里加一行,断言逻辑一个字都不用动。升级:t.Run 拆成独立子测试上面的版本还有个小缺点:所有用例挤在一个TestFormatDuration里,测试输出看不清哪个子用例过了、哪个挂了,也没法单独跑某一个。用t.Run给每个用例开一个子测试就解决了:funcTestFormatDuration(t*testing.T){tests:[]struct{namestringinputintwantstringwantErrbool}{{name:零秒,input:0,want:0h0m0s},{name:一分钟,input:60,want:0h1m0s},{name:时分秒齐全,input:3661,want:1h1m1s},{name:负数报错,input:-1,wantErr:true},}for_,tt:rangetests{// 每个用例一个子测试,名字就是 tt.namet.Run(tt.name,func(t*testing.T){got,err:FormatDuration(tt.input)if(err!nil)!tt.wantErr{t.Fatalf(是否报错 %v, 期望 %v,err!nil,tt.wantErr)}ifgot!tt.want{t.Errorf(得到 %q, 期望 %q,got,tt.want)}})}}t.Run的好处:输出里每个子测试独立显示,--- FAIL: TestFormatDuration/负数报错一眼定位。可以只跑某一个:go test -run TestFormatDuration/时分秒齐全。子测试之间隔离,某个子测试t.Fatalf只终止它自己,不影响其余子测试继续跑。跑一下看输出:$ gotest-v-runTestFormatDurationRUN TestFormatDurationRUN TestFormatDuration/零秒RUN TestFormatDuration/一分钟RUN TestFormatDuration/时分秒齐全RUN TestFormatDuration/负数报错 --- PASS: TestFormatDuration(0.00s)--- PASS: TestFormatDuration/零秒(0.00s)--- PASS: TestFormatDuration/一分钟(0.00s)--- PASS: TestFormatDuration/时分秒齐全(0.00s)--- PASS: TestFormatDuration/负数报错(0.00s)PASS一个必须知道的坑:循环变量与 t.Parallel如果你想让子测试并行跑(t.Parallel()),在Go 1.22 之前有个经典陷阱:所有子测试闭包共享同一个循环变量tt,并行执行时它们读到的都是循环结束后的最后一个值。老代码里你会看到这种「重新赋值」的写法来规避:for_,tt:rangetests{tt:tt// Go 1.22 前必须这行,给每次迭代一份独立副本t.Run(tt.name,func(t*testing.T){t.Parallel()// 标记为并行,和其他并行子测试一起跑got,_:FormatDuration(tt.input)ifgot!tt.want{t.Errorf(得到 %q, 期望 %q,got,tt.want)}})}Go 1.22 起循环变量每次迭代都是新的,tt : tt这行可以删掉了。但如果你的项目还跑在老版本,或者你不确定别人的环境,留着它最保险——它无害。不加t.Parallel()时子测试是串行的,不受这个坑影响,但加了并行又忘了处理循环变量,就会得到「所有用例都在测最后一行数据」的诡异结果。小结别复制粘贴断言:把用例抽成结构体切片(表),断言逻辑只写一遍,循环套用。表里给每个用例一个name字段,出错能一眼定位是哪个用例。用t.Run(tt.name, ...)拆成子测试:输出清晰、可单独跑、子测试之间隔离。收集所有失败用t.Errorf(继续跑),需要立即终止当前子测试才用t.Fatalf。并行子测试注意循环变量陷阱:Go 1.22 前要写tt : tt,1.22 起可省;不确定就留着。一句话记忆:用例是数据、断言是代码,一张表 t.Run就是 Go 测试的标准姿势。

相关新闻

仓颉开源社区学习赛火热开赛!提交 PR 领京东卡,等你来抢!

仓颉开源社区学习赛火热开赛!提交 PR 领京东卡,等你来抢!

你有没有想过——自己的代码被成千上万的开发者使用,会是什么感觉?又或者,你一直想参与开源,却总觉得门槛太高、不知从何下手? 「仓颉开源社区学习赛」正是为这样的你准备的。 简单来说就是:在仓颉开源社区…

2026/8/1 20:24:13 阅读更多 →
OSI七层模型深度解析:从网络通信原理到实战排查指南

OSI七层模型深度解析:从网络通信原理到实战排查指南

1. 项目概述:从“七层楼”看透网络通信的本质干了这么多年网络运维和开发,我发现很多朋友一提到OSI参考模型就头疼,觉得它是一堆抽象的概念,离实际工作很远。其实恰恰相反,无论你是刚入行的网工、正在学习后端开发的程…

2026/8/1 20:23:13 阅读更多 →
EMCCD vs.sCMOS 巅峰对决,冷原子相机选型指南!

EMCCD vs.sCMOS 巅峰对决,冷原子相机选型指南!

EMCCD解决了第一代单原子成像“看见光子”的问题,而sCMOS解决了下一阶段“规模化读取量子信息”的问题。对于冷原子实验而言,真正重要的不是选择“参数最好”的相机,而是选择与实验系统最匹配的成像解决方案。 冷原子相机选型要素 1. 选择合适…

2026/8/1 20:23:13 阅读更多 →

最新新闻

终极指南:DankDroneDownloader - 重新掌控你的无人机固件自由

终极指南:DankDroneDownloader - 重新掌控你的无人机固件自由

终极指南:DankDroneDownloader - 重新掌控你的无人机固件自由 【免费下载链接】DankDroneDownloader A Custom Firmware Download Tool for DJI Drones Written in C# 项目地址: https://gitcode.com/gh_mirrors/da/DankDroneDownloader 你是否曾经因为无人机…

2026/8/1 21:52:56 阅读更多 →
杰理开发入门分享:工具链选型与调试实践

杰理开发入门分享:工具链选型与调试实践

摘要初次接触杰理芯片开发,工具链的选择和调试思维的建立是入门的第一道关卡。与常见的ARM架构MCU不同,杰理芯片采用自研DSP内核,开发方式和调试手段存在明显差异。本文从实际开发角度,介绍几款常用工具及使用要点,帮助…

2026/8/1 21:51:56 阅读更多 →
如何快速部署YuYuWechat:面向新手的微信自动化消息管理完整指南

如何快速部署YuYuWechat:面向新手的微信自动化消息管理完整指南

如何快速部署YuYuWechat:面向新手的微信自动化消息管理完整指南 【免费下载链接】YuYuWechat 一个让微信(非WEB版)定时循环发送消息/文件(cron表达式精确到分钟),批量群发消息,定时检查聊天记录…

2026/8/1 21:51:56 阅读更多 →
3步掌握ComfyUI-LTXVideo:新手也能快速上手的AI视频生成终极指南

3步掌握ComfyUI-LTXVideo:新手也能快速上手的AI视频生成终极指南

3步掌握ComfyUI-LTXVideo:新手也能快速上手的AI视频生成终极指南 【免费下载链接】ComfyUI-LTXVideo LTX-Video Support for ComfyUI 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-LTXVideo 你是否曾被AI视频生成的技术门槛吓退?是…

2026/8/1 21:51:56 阅读更多 →
2026六安黄金回收白银回收铂金回收工商备案可查全城上门回收旧金老店联系方式推荐

2026六安黄金回收白银回收铂金回收工商备案可查全城上门回收旧金老店联系方式推荐

2026六安黄金白银铂金回收实测榜单|工商备案可查全城上门回收旧金老店联系方式推荐 六安黄金回收哪家靠谱|工商公安双备案中检认证实体门店 六安贵金属回收店铺近年来遍地丛生,行业套路层出不穷,不少市民变现时遭遇虚高报价、克扣…

2026/8/1 21:51:56 阅读更多 →
RK3588 (ARM64) 绿联 AX900 USB 无线网卡驱动安装教程

RK3588 (ARM64) 绿联 AX900 USB 无线网卡驱动安装教程

RK3588 (ARM64) 绿联 AX900 USB 无线网卡驱动安装教程芯片方案:AIC 8800D80 (爱科微) 适用平台:Rockchip RK3588 / ARM64 Linux 测试环境:LubanCat-5 / Debian 12 Bookworm / Linux 6.1.99-rk3588 网卡型号:绿联 CM763 AX900 (USB…

2026/8/1 21:51:56 阅读更多 →

日新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/1 0:00:48 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/1 0:00:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/1 0:00:48 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/8/1 13:02:46 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/8/1 5:19:34 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/8/1 10:33:33 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/1 0:00:48 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/1 0:00:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/1 0:00:48 阅读更多 →