helper

package
v2.2.44 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 22, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package helper —— assert.go

极简的断言/工具函数。注意:本文件不是替代 testify 的"完整断言库"——testify 已经被允许引入,所有"复杂断言"请直接调用 testify/require 或 testify/assert。

本文件只承担:

  • 那些 testify 不直接覆盖的"工程化断言"(goroutine 增量、内存增量、duration 范围);
  • 测试中频繁使用、不希望反复 import "fmt" 拼字符串的小工具。

Package helper —— deadline.go

提供"事件同步"原语,替代测试中常见的 time.Sleep。

设计动机(对应任务约束:"必须避免 sleep-based synchronization,优先事件同步"):

❌ time.Sleep(100*time.Millisecond) // 慢机器会假阴性,快机器会浪费时间
✅ helper.WaitFor(t, 2*time.Second, cond)

所有 Wait* 函数都遵循统一的契约:

  • 在 timeout 内反复检查条件,命中即返回;
  • 超时未命中则 t.Fatalf,便于栈帧上溯到调用点;
  • 内部 backoff 从 250µs 起步指数增长到 5ms,让 hot loop 不会刷爆 CPU。

Package helper 提供 go-reqx 测试体系(tests/)共用的脚手架工具。

设计原则:

  1. 所有 tests/ 下的测试都通过本包获取并发限流、事件同步、随机数、 临时目录、TIME_WAIT 友好的端口分配、leak 白名单等基础能力, 避免在测试文件里反复编写脚手架代码。

  2. 严格遵循"可控、可观察、可回收"三原则: - 可控:所有并发上限、超时阈值、grace 时间均参数化或环境变量化; - 可观察:失败时给出能直接定位的字段(goroutine 增量、文件描述符差等); - 可回收:所有 helper 持有的资源都在 t.Cleanup 中显式释放, 不依赖 GC/finalizer,也不在测试退出后留下后台 goroutine。

  3. 默认值与本机资源(16C/24T、10GB 可用内存)匹配: - 单元测试并发上限 16; - 集成测试并发上限 32; - concurrency 测试并发上限 64; - benchmark 分级(smoke≤1k / normal≤10k / extreme 必须 GOREQX_EXTREME=1 且 testing.Short()==false)。

本包仅依赖标准库与 stretchr/testify,不引入任何 monkey patch / runtime hack。

Package helper —— env.go

集中所有 GOREQX_* 测试期环境变量的解析与默认值。

严格契约:

  1. 测试代码不应散落 os.Getenv("GOREQX_*"), 必须经过本文件统一获取。
  2. 每个 EnvXxx 函数都给出"默认值 + 含义 + 影响范围"三段注释,便于 grep。
  3. 解析失败一律走默认值(不会让用户的笔误把测试卡死),但会通过 EnvDump 暴露当前生效值, 让 CI 日志能看到。

Package helper —— expect.go

"请求期望" 与 "响应期望" 的轻量比对工具。

用途:在 testkit/transport.RecordingRoundTripper 与 testkit/server 收到的 请求记录上,统一做"我期望的 method/path/header/body 是否匹配"的断言。

设计:

  • 字段为 nil/零值 时表示"不关心",命中过的字段才参与匹配;
  • 失败时一次性输出全部不一致项(不会逐个 require.Equal 让用户看不到全貌)。

Package helper —— leakcheck.go

提供"轻量版" goroutine 泄漏检测器。

与 Batch 2 中 testkit/leak 的关系:

  • 本文件提供"零依赖"版本:基于 runtime.Stack 的 goroutine 快照/差分, 可以在任何场景使用(包括非 *testing.T 调用方);
  • testkit/leak 包会在此基础上叠加 goleak(go.uber.org/goleak)的更精细的 白名单与 IgnoreTopFunction 机制,并提供 fd / cleanup 检测能力。

这个文件只做"goroutine 增量是否合理"的简单验证,依赖 stdlib,绝不引入额外第三方包。

⚠️ 注意:runtime.Stack 在 goroutine 较多(>1000)时较慢,请合理控制使用频率。

Package helper —— parallel.go

提供"带上限、带 panic 兜底、带超时"的并发测试调度器。

为何不直接用 t.Parallel + WaitGroup?

  1. t.Parallel 只控制"测试函数级"并发,无法限制单测内部 fork 的 goroutine 数量;
  2. 直接 WaitGroup 没有 panic 兜底,单个 worker panic 会让 -race 报告变形;
  3. 没有上限钳制时,循环里 go 出 1024 个 goroutine 在 16C24T 机器上会出现严重的 调度抖动,Race detector 还会进一步放大;
  4. 为了配合 R10/R11/R8(concurrent request reuse / request clone / pool starvation) 等用例的"稳定可重复",需要确定性的 worker pool 调度模式。

设计:

  • RunParallelN(t, total, parallel, fn) :跑 total 次,最多 parallel 并发;
  • RunBoundedParallel(t, ctx, parallel, fn):基于 ctx 的"持续并发"模型,ctx 取消时收敛;
  • 每个 worker 包一层 recover:panic 通过 t.Errorf 转为测试失败,不让进程崩溃;
  • 退出前等所有 worker 真正返回(包括 panic 路径),保证 leak 检测可见。

Package helper —— portalloc.go

提供"TIME_WAIT 友好"的 TCP 端口分配辅助。

背景:

测试期会大量短连接 → 大量 TIME_WAIT;
若反复用同一个 fixed port,操作系统侧会出现 "address already in use" 假阳性。

策略:

  1. 默认调用 net.Listen("tcp", "127.0.0.1:0") 让内核选端口;
  2. 进程内维护一个最近使用集合(LRU + 过期),避免在短时间内归还同一个端口给下个测试;
  3. 返回的 *net.TCPListener 由调用方持有;如调用方需要的是"端口号",请使用 PickPort。

为何不用一个端口段(例如 30000~40000)轮询?

  • 跨平台(Windows/Mac/Linux)的 ephemeral 范围不同;
  • 同机器跑多个 go test 会冲突;
  • 0 让内核处理才是真正稳定方案。

Package helper —— random.go

测试体系的随机数源。

设计原则:

  1. 默认使用 crypto/rand 派生 seed,确保不同进程/不同跑次的随机数不同;
  2. 同一个 *testing.T 内可通过 Seed(t) 显式播种以保证可重放(CI 失败 → 本地复现);
  3. 单 goroutine 用 *rand.Rand(math/rand/v2),并发场景请每个 goroutine 自己持有一份;
  4. 不引入 v1 math/rand 的全局锁路径,避免 benchmark 受影响。

Package helper —— retry.go

提供"最终一致性"断言能力:Eventually / Consistently。

与 deadline.go 的关系:

  • deadline.WaitFor 关注"事件何时发生",超时直接 t.Fatalf;
  • retry.Eventually 关注"断言何时成立",期间允许大量失败,最终成立即可;
  • retry.Consistently 关注"断言在一段时间内持续成立"。

这两个原语主要服务于:

  • leak 检测:"goroutine 数应在 1s 内回落到基线";
  • pool 行为:"idle 连接数应在 IdleConnTimeout 内归零";
  • chaos 收敛:"error rate 应在 stop 之后下降到 0"。

与现成的 testify/require.Eventually 相比,本实现:

  • 显式记录每一轮的失败原因,t.Logf 输出最近 N 条诊断;
  • 保证 backoff 与 deadline.go 一致,可叠加使用;
  • 不依赖 testify(部分上层场景需要在非 *testing.T 路径上断言)。

Package helper —— short.go

统一处理 testing.Short() 与"重型用例守门"。

设计动机:

go test ./...                  // 跑 Level 0 + Level 1(unit/integration/concurrency/security/...)
go test -short ./...           // 跑 Level 0,只快路径
go test -tags=bench_normal ... // 跑 benchmark normal
GOREQX_EXTREME=1 go test ...   // 解锁 extreme(仅在 !testing.Short() 时才会真正执行)

测试代码统一调用 helper.Skip*,永远不要手写 t.Skip(reason)。 这样所有"为何被跳过"的入口都集中在本文件,便于统一检索与维护。

Package helper —— tempdir.go

提供"测试期临时目录"的封装,统一生成 multipart / tar / SaveToFile 等场景所需的 文件树,避免每个测试自己 ioutil 拼路径。

与 testing.T.TempDir 的关系:

  • 直接复用 t.TempDir(),由 testing 自动在测试结束时清理;
  • 在它之上提供 WriteFile / WriteRandomFile / Tree 等便捷接口;
  • 不引入额外清理逻辑,避免双清理与 race。

Index

Constants

View Source
const (
	BenchSmokeMaxReq   = 1_000
	BenchNormalMaxReq  = 10_000
	BenchExtremeMaxReq = 1_000_000
)

关于 benchmark 三档的"requests 上限"硬约束。 测试代码可以在此基础上再做下调,但绝不允许超过。

Variables

This section is empty.

Functions

func AcquireListener

func AcquireListener(tb testing.TB) (net.Listener, int)

AcquireListener 在 127.0.0.1 上绑定一个内核分配的端口,并返回 listener + 端口号。

调用方须负责 Close listener;本包不会替你 close。

内部副作用:把分配到的端口记入"最近使用集合",避免短时间内重复分配(虽然内核也不会 立刻给同一端口,但记录后我们能在测试日志中诊断"是不是同一端口反复抢占")。

func AssertCountInRange

func AssertCountInRange(t testing.TB, label string, n, lo, hi int)

AssertCountInRange 断言:实际计数 n 落在 [lo, hi]。

适合"重试次数应在 1~3 次之间"等区间断言。

func AssertDurationAtLeast

func AssertDurationAtLeast(t testing.TB, label string, actual, min time.Duration)

AssertDurationAtLeast 断言:actual >= min。

func AssertDurationAtMost

func AssertDurationAtMost(t testing.TB, label string, actual, max time.Duration)

AssertDurationAtMost 断言:actual <= max。

func AssertDurationWithin

func AssertDurationWithin(t testing.TB, label string, actual, min, max time.Duration)

AssertDurationWithin 断言:实际耗时 actual 在 [min, max] 区间。 用于"超时配置应在 X 时间内生效"等确定性检查。

func AssertNoGoroutineGrowth

func AssertNoGoroutineGrowth(t testing.TB, tolerance int, gracePeriod time.Duration, fn func())

AssertNoGoroutineGrowth 断言:在 fn 执行前后,runtime.NumGoroutine() 增量 不超过 tolerance。

⚠️ 该断言较"粗":不区分是哪个 goroutine(用于细粒度判定请用 testkit/leak)。 适合作为 happy-path 用例的快速冒烟检查。

gracePeriod 给 net/http 等后台 idle 连接 reaper 留缓冲时间,建议 50~200ms。

func Consistently

func Consistently(t testing.TB, stableFor time.Duration, cond func(record func(format string, args ...any)) bool)

Consistently 在 stableFor 内反复执行 cond;任一轮失败即 t.Fatalf。

注意:stableFor 不能太长(建议 100ms~500ms),否则会显著拉长测试总时长。

cond 同 Eventually 的签名(含 record 回调)。

func EnvChaosTimeout

func EnvChaosTimeout() time.Duration

EnvChaosTimeout 返回 chaos 用例的硬超时(用于 context.WithTimeout 兜底),默认 30s。

func EnvConcurrencyParallel

func EnvConcurrencyParallel() int

EnvConcurrencyParallel 返回 concurrency 测试并发上限。

  • 默认 64;
  • 可被 GOREQX_RACE_GOROUTINES 覆盖;
  • 硬上限 256(远超过 NumCPU 是为了暴露调度问题,但 256 是天花板,避免本机被打爆)。

func EnvDump

func EnvDump() string

EnvDump 返回当前所有 GOREQX_* 配置的字符串快照,便于在 CI 日志或 t.Logf 中打印。

func EnvExtreme

func EnvExtreme() bool

EnvExtreme 报告是否打开了 extreme 用例开关。

⚠️ 注意:仅看环境变量;testing.Short() 检查由 RequireExtreme 完成。

func EnvFDLeakCheck

func EnvFDLeakCheck() bool

EnvFDLeakCheck 报告是否启用 fd leak 检测。 仅在 Linux 上可靠;其他平台即使打开也只会做 best-effort。

func EnvFuzzTime

func EnvFuzzTime() time.Duration

EnvFuzzTime 返回 fuzz 单 target 时长。默认 30s,最小 1s。

func EnvHeavy

func EnvHeavy() bool

EnvHeavy 报告是否打开了重型用例开关。

func EnvIntegrationParallel

func EnvIntegrationParallel() int

EnvIntegrationParallel 返回集成测试并发上限。

  • 默认 32;
  • 可被 GOREQX_INTEGRATION_GOROUTINE 覆盖;
  • 上限:runtime.NumCPU()*8,且不超过硬约束 64。

func EnvUnitParallel

func EnvUnitParallel() int

EnvUnitParallel 返回单元测试并发上限。

  • 默认 16;
  • 可被 GOREQX_UNIT_GOROUTINE 覆盖;
  • 始终不超过 runtime.NumCPU()*4,避免在低核机器上过度调度。

func Eventually

func Eventually(t testing.TB, timeout time.Duration, cond func(record func(format string, args ...any)) bool)

Eventually 在 timeout 内反复执行 cond,命中即返回。 期间记录最后 maxKeep 条失败描述(msg 由 cond 通过 record 上报),失败时一并打印。

cond 的签名:func(record func(format string, args ...any)) bool

  • record 是诊断回调;cond 内部可在每次失败时调用一次,便于排查;
  • 返回 true 即成功;返回 false 表示本轮未命中,继续重试。

func IsWaitTimeout

func IsWaitTimeout(err error) bool

IsWaitTimeout 判定一个 error 是否来自 WaitForCtx 的超时。

func LocalAddr

func LocalAddr(port int) string

LocalAddr 返回 "127.0.0.1:port" 形式的地址字符串。

func LogEnvOnce

func LogEnvOnce(printf func(format string, args ...any))

LogEnvOnce 在 TestMain / 第一个被执行的 helper.* 入口打印一次环境配置摘要。 避免每个 _test.go 文件都重复打印。

func MaxInt

func MaxInt(a, b int) int

MaxInt 返回 a, b 中较大者;用于本包内部计算钳位。

func MinInt

func MinInt(a, b int) int

MinInt 返回 a, b 中较小者。

func MustHappen

func MustHappen[T any](t testing.TB, timeout time.Duration, ch <-chan T, msg string)

MustHappen 等待 done 在 timeout 内被 close / 收到值;超时则失败。

适合"goroutine 完成"事件:

done := make(chan struct{})
go func() { defer close(done); ... }()
helper.MustHappen(t, 2*time.Second, done, "producer goroutine 应已退出")

func MustNotHappen

func MustNotHappen[T any](t testing.TB, quietFor time.Duration, ch <-chan T, msg string)

MustNotHappen 在 quietFor 内反复确认 ch 未触发;触发即失败。

适合"goroutine 必须 still 活着 / 不应在 X 内退出"的反向断言。

注意:本函数会阻塞 quietFor 时长,请合理选择长度(建议 50ms~200ms)。

func NewDeterministicRand

func NewDeterministicRand(s1, s2 uint64) *rand.Rand

NewDeterministicRand 用调用方指定的两个 seed 构造确定性 rand。 用于 fuzz / chaos 中"已经从外部拿到 seed"的场景。

func NewRand

func NewRand(tb testing.TB) *rand.Rand

NewRand 返回一个独立的 *rand.Rand。

seed 来源:

  1. 环境变量 GOREQX_TEST_SEED 非空:用户显式指定(用于复现失败用例);
  2. 否则使用 crypto/rand 派生两个 uint64 作为种子,保证每次进程不同。

在测试代码里:

r := helper.NewRand(t)
v := r.IntN(100)

func PickPort

func PickPort(tb testing.TB) int

PickPort 仅返回一个"刚刚被内核选过的端口号"——立即关闭 listener 后给出。

⚠️ 由于 close 后端口短时间会进入 TIME_WAIT,调用方需要立即在新进程/服务上 bind 才能复用,否则可能出现 "address already in use"。本函数仅供"必须先知道端口才能配置" 的少数场景;优先使用 AcquireListener。

func RandASCII

func RandASCII(r *rand.Rand, n int) string

RandASCII 返回 n 字节可打印 ASCII(0x20~0x7E)。 适合"我要一段不会被各类编码吃掉的随机文本"的场景。

func RandBytes

func RandBytes(r *rand.Rand, n int) []byte

RandBytes 返回 n 字节的随机数据。

仅在测试中使用;安全敏感路径请直接走 crypto/rand。

func RecentlyUsedPorts

func RecentlyUsedPorts() []int

RecentlyUsedPorts 返回当前进程最近 avoidWindow 内分配过的端口列表副本。 主要供调试与日志使用。

func RequireExtreme

func RequireExtreme(tb testing.TB)

RequireExtreme 在 GOREQX_EXTREME != "1" 或 testing.Short() == true 时跳过。

用于 destructive / extreme load 用例:socket flood、slowloris flood、 1M 量级 benchmark、retry 风暴等。

严格契约:

  • 必须显式 export GOREQX_EXTREME=1;
  • 必须不在 -short 模式下;
  • 满足上述两条才允许真正执行。

func RequireHeavy

func RequireHeavy(tb testing.TB)

RequireHeavy 在 GOREQX_TEST_HEAVY != "1" 时跳过用例。 用于"中等强度"测试:跑得不算慢(< 5s)但默认仍想保持安静。

与 SkipIfShort 的差异:

  • SkipIfShort 看 -short 标志;
  • RequireHeavy 看用户是否显式打开了重型测试开关。

func RequireLinux

func RequireLinux(tb testing.TB, goos string)

RequireLinux 在非 Linux 平台跳过,用于 /proc/self/fd 等系统相关用例。 调用方需要显式传入当前 GOOS(由调用侧 runtime.GOOS 注入),避免本包直接 在 build tag 上做切割。

func RunBoundedParallel

func RunBoundedParallel(t testing.TB, ctx context.Context, parallel int, fn func(workerID int, iter int64) error, opts ...ParallelOptions)

RunBoundedParallel 在最多 parallel 个 goroutine 上反复执行 fn,直到 ctx 取消。

与 RunParallelN 的差异:

  • 没有 total 上限,由 ctx 决定何时停止;
  • 适合"压一段时间"的用例(chaos / soak / starvation)。

fn 签名:func(workerID int, iter int64) error

  • workerID 固定(0..parallel-1),方便定位;
  • iter 是该 worker 的局部循环计数(从 0 递增)。

func RunParallelN

func RunParallelN(t testing.TB, total, parallel int, fn func(taskIdx int) error, opts ...ParallelOptions)

RunParallelN 在最多 parallel 个 goroutine 上把 fn 跑 total 次。

调度语义:

  • 启动 parallel 个固定 worker;
  • 每个 worker 从一个共享 atomic 计数器领取 task index;
  • 取到的 index >= total 则退出;
  • 任意 worker panic 会被 recover,并转成 t.Errorf;FailFast 模式下还会取消其余 worker。

入参 fn 的签名:func(taskIdx int) error

  • 返回 non-nil err 会被 t.Errorf 报告;
  • panic 同样会被报告,并附带 stack;
  • fn 内部禁止调用 t.FailNow / t.Fatal(goroutine 内 t.Fatal 会 panic 不可恢复); 如需断言,请返回 error 或调用 testify/require.NoError 之外的 assert.* 系列。

func SkipIfShort

func SkipIfShort(tb testing.TB, reason string)

SkipIfShort 在 testing.Short() 为 true 时跳过当前用例。 用于 Level 1+ 中那些会跑数百毫秒以上的子用例,确保 -short 模式仍然清爽。

func WaitFor

func WaitFor(t testing.TB, timeout time.Duration, cond func() bool)

WaitFor 在 timeout 内反复轮询 cond,命中(返回 true)即返回 nil;超时则失败。

cond 的实现应当幂等且廉价(atomic 比较、map 长度等);不要在 cond 内做 IO。

func WaitForCtx

func WaitForCtx(ctx context.Context, timeout time.Duration, cond func() bool) error

WaitForCtx 是 WaitFor 的 context 变体:ctx 取消即返回 ctx.Err(),timeout 同上。

主要用于"在 chaos 用例里等待某个收敛条件,但希望尊重 ctx 早退"。

Types

type BenchTier

type BenchTier int

BenchTier 表示当前进程要执行的 benchmark 强度档位。

const (
	BenchTierSmoke BenchTier = iota // 默认
	BenchTierNormal
	BenchTierExtreme
)

func EnvBenchTier

func EnvBenchTier() BenchTier

EnvBenchTier 解析当前 benchmark 档位,默认 smoke。

取值映射:

smoke   → BenchTierSmoke   (默认)
normal  → BenchTierNormal
extreme → BenchTierExtreme(仍需 GOREQX_EXTREME=1 才会真正放行 extreme 测试)

func (BenchTier) String

func (t BenchTier) String() string

String 返回档位名称,便于日志/失败信息打印。

type CountdownLatch

type CountdownLatch struct {
	// contains filtered or unexported fields
}

CountdownLatch 是一个轻量倒计时同步原语,N 减到 0 时 Done() 通道被关闭。

用法:

cd := helper.NewCountdownLatch(3)
go func() { ...; cd.Tick() }()
go func() { ...; cd.Tick() }()
go func() { ...; cd.Tick() }()
helper.MustHappen(t, time.Second, cd.Done(), "三个 worker 都应到位")

func NewCountdownLatch

func NewCountdownLatch(n int64) *CountdownLatch

NewCountdownLatch 构造一个 N 步倒计时;N <= 0 时立刻完成。

func (*CountdownLatch) Done

func (c *CountdownLatch) Done() <-chan struct{}

Done 返回完成信号 channel。

func (*CountdownLatch) Remaining

func (c *CountdownLatch) Remaining() int64

Remaining 返回剩余 tick 次数(用于诊断)。

func (*CountdownLatch) Tick

func (c *CountdownLatch) Tick()

Tick 减一;恰好减到 0 时关闭 Done channel。多次到 0 不会重复关闭。

type GoroutineSnap

type GoroutineSnap struct {
	// contains filtered or unexported fields
}

GoroutineSnap 保存某一时刻的 goroutine 快照。

func CaptureGoroutines

func CaptureGoroutines() *GoroutineSnap

CaptureGoroutines 抓取当前进程的全部 goroutine 栈。

实现细节:

  • runtime.Stack(buf, true) 是同步的、O(N);
  • 这里采用倍增 buf 直到成功(避免被截断);
  • 单条 goroutine 摘要保留 "goroutine N [state]: TopFrame" 一行用于差分诊断。

func (*GoroutineSnap) Check

func (s *GoroutineSnap) Check(t testing.TB, opts ...LeakCheckOptions)

Check 在 fn 执行后断言 goroutine 增量满足要求。

调用模式:

defer helper.CaptureGoroutines().Check(t, helper.LeakCheckOptions{Tolerance: 1})
... 测试代码 ...

实现:

  1. 在 Grace 期间反复重抓快照,给"正在退出"的 goroutine 时间真正 return;
  2. 把当前快照与 baseline 做 diff,过滤白名单后看剩余条数 > Tolerance 即失败;
  3. 失败时打印 diff 详情,便于人工排查。

func (*GoroutineSnap) Count

func (s *GoroutineSnap) Count() int

Count 返回快照时刻的 NumGoroutine。

func (*GoroutineSnap) Stacks

func (s *GoroutineSnap) Stacks() []string

Stacks 返回每条 goroutine 的简化栈摘要切片副本。

type LeakCheckOptions

type LeakCheckOptions struct {
	// Tolerance 允许的 goroutine 增量(默认 0)。
	Tolerance int
	// Grace 是为新 goroutine 退出预留的等待时间(默认 200ms)。
	Grace time.Duration
	// IgnoreTopFunc 是允许出现在差异栈中的"top frame"前缀白名单。
	// 命中即不计入增量。
	IgnoreTopFunc []string
	// IgnoreContains 是允许出现在差异栈任意位置的子串白名单。
	IgnoreContains []string
}

LeakCheckOptions 控制 GoroutineSnap.Check 的容忍度与白名单。

type ParallelOptions

type ParallelOptions struct {
	// FailFast=true 时,任何 worker panic / 自报 error 会立刻 cancel 内部 ctx,
	// 让其他 worker 尽快退出。默认 true。
	FailFast bool

	// PerWorkerTimeout 给每个 worker 函数的运行时间上限。
	// 0 表示不强制(注意:仍然受外层 ctx 影响)。
	PerWorkerTimeout time.Duration

	// OnStart 在每个 worker 开始前调用一次,便于注入 trace。
	OnStart func(workerID int)
	// OnDone 在每个 worker 退出(无论成败)前调用一次。
	OnDone func(workerID int, err error)
}

ParallelOptions 控制 RunParallelN / RunBoundedParallel 的细节。

type RequestExpect

type RequestExpect struct {
	Method       string                                                     // 期望的 method(大小写不敏感比较)
	URLPath      string                                                     // 期望的 URL.Path(精确)
	URLPathHas   string                                                     // 期望 URL.Path 包含此子串
	QueryEquals  map[string]string                                          // query 名 → 唯一期望值
	QueryHas     []string                                                   // query 必须存在的 key 列表
	HeaderEquals map[string]string                                          // header → 期望值(CanonicalKey 后比较)
	HeaderHas    []string                                                   // header 必须存在的 key 列表
	BodyEquals   []byte                                                     // 完整 body 字节匹配
	BodyHas      []string                                                   // body 必须包含的子串
	Custom       func(req *http.Request, body []byte) (ok bool, msg string) // 兜底自定义断言
}

RequestExpect 描述对一次发出去的 HTTP 请求的期望。

字段都是"期望值",nil/空 表示不校验。

func (RequestExpect) Match

func (e RequestExpect) Match(t testing.TB, req *http.Request, body []byte)

Match 把请求与期望对比;不一致时 t.Fatalf 并打印所有差异。

body 由调用方提前读出来传入;调用方负责处理 body 的复用与重新 Set。

type ResponseExpect

type ResponseExpect struct {
	StatusCode int               // == 0 不校验
	HeaderHas  []string          // header 必须存在
	HeaderEq   map[string]string // header 期望值
	BodyEq     []byte            // body 完整字节
	BodyHas    []string          // body 必须包含子串
	Custom     func(resp *http.Response, body []byte) (ok bool, msg string)
}

ResponseExpect 描述对客户端拿到的响应的期望。

func (ResponseExpect) Match

func (e ResponseExpect) Match(t testing.TB, resp *http.Response, body []byte)

Match 比较响应与期望。

注意:调用方在传入 body 前必须自己关闭/复用 resp.Body;本函数不重读。

type TempTree

type TempTree struct {
	// contains filtered or unexported fields
}

TempTree 表示一棵临时目录。

func NewTempTree

func NewTempTree(tb testing.TB) *TempTree

NewTempTree 创建一棵以 t.TempDir() 为根的临时目录。

测试结束后由 testing 自动清理整棵目录,调用方无需手动 Remove。

func (*TempTree) List

func (t *TempTree) List() []string

List 返回根目录下所有文件的相对路径(按字典序),便于断言树状态。

func (*TempTree) Mkdir

func (t *TempTree) Mkdir(rel string) string

Mkdir 在树内创建一个空目录(含中间目录)。

func (*TempTree) Path

func (t *TempTree) Path(parts ...string) string

Path 拼接根目录下的相对路径,自动 mkdir -p 父目录。

func (*TempTree) Root

func (t *TempTree) Root() string

Root 返回根目录绝对路径。

func (*TempTree) SeedTree

func (t *TempTree) SeedTree(files map[string][]byte)

SeedTree 一次性写入多个文件,map 的 key 是相对路径,value 是内容。 适合在表驱动测试里集中初始化。

func (*TempTree) String

func (t *TempTree) String() string

String 输出整棵树的简洁描述,便于失败诊断。

func (*TempTree) WriteFile

func (t *TempTree) WriteFile(rel string, content []byte) string

WriteFile 写入指定相对路径的文件,content 为字节内容。 返回文件的绝对路径。

func (*TempTree) WriteRandomFile

func (t *TempTree) WriteRandomFile(rel string, size int64) string

WriteRandomFile 写入一个 size 字节的伪随机内容文件(crypto/rand 派生)。

注意:crypto/rand 在大尺寸(>10MB)时较慢。如对内容随机度无要求,建议自行 io.CopyN 自一个固定 reader,本函数不在此处暴露弱随机模式以避免歧义。

func (*TempTree) WriteString

func (t *TempTree) WriteString(rel, content string) string

WriteString 是 WriteFile 的字符串便捷版本。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL