zig-testing
Zig 测试与调试技能。涉及 std.testing 的断言、测试组织、内存泄漏检测、以及 std.debug 的日志、堆栈回溯。在需要编写测试、调试代码、诊断问题时调用。
Zig 测试与调试技能。涉及 std.testing 的断言、测试组织、内存泄漏检测、以及 std.debug 的日志、堆栈回溯。在需要编写测试、调试代码、诊断问题时调用。
基于 std.testing 和 std.debug 的质量保障工具(Zig 0.16.0)。
zig version)zig-build-system 技能zig-0.16 技能本技能不收集、存储或传输任何用户数据。
步骤 1. 声明测试 — test "name" { ... }
步骤 2. 使用断言 — expect, expectEqual, expectEqualStrings
步骤 3. 运行测试 — zig test src/main.zig 或 zig build test
步骤 4. 检查结果 — 通过/失败/泄漏
| 断言 | 用途 |
|------|------|
| expect(bool) | 条件为真 |
| expectEqual(expected, actual) | 浅相等(peer type) |
| expectEqualDeep(expected, actual) | 深相等(递归比较) |
| expectEqualStrings(expected, actual) | 字符串相等(带 diff) |
| expectEqualSlices(T, expected, actual) | 切片相等 |
| expectError(error, result) | 返回特定错误 |
| expectApproxEqAbs(expected, actual, eps) | 浮点近似(绝对误差) |
| expectApproxEqRel(expected, actual, eps) | 浮点近似(相对误差) |
| expectFmt(expected, template, args) | 格式化输出匹配 |
| expectStringStartsWith(actual, prefix) | 字符串前缀 |
| expectStringEndsWith(actual, suffix) | 字符串后缀 |
test "basic assertions" {
try std.testing.expect(true);
try std.testing.expectEqual(@as(u32, 42), @as(u32, 42));
try std.testing.expectEqualStrings("hello", "hello");
try std.testing.expectEqualSlices(u8, &[_]u8{ 1, 2 }, &[_]u8{ 1, 2 });
try std.testing.expectEqualDeep(
struct{ x: i32, y: i32 }{ .x = 1, .y = 2 },
struct{ x: i32, y: i32 }{ .x = 1, .y = 2 },
);
}
test "float comparison" {
try std.testing.expectApproxEqAbs(@as(f32, 1.0), 1.0001, 0.001);
try std.testing.expectApproxEqRel(@as(f64, 100.0), 99.5, 0.01);
}
test "error handling" {
const result: anyerror!i32 = error.SomeError;
try std.testing.expectError(error.SomeError, result);
}
const std = @import("std");
const expect = std.testing.expect;
test "inline test" {
try expect(1 + 1 == 2);
}
/// Adds two numbers.
///
/// ```
/// const result = add(2, 3);
/// try std.testing.expectEqual(@as(i32, 5), result);
/// ```
fn add(a: i32, b: i32) i32 {
return a + b;
}
# 运行名称包含 "http" 的测试
zig test src/main.zig --test-filter "http"
# 在 build.zig 中过滤
const tests = b.addTest(.{
.root_module = mod,
.filters = &.{"specific_test"},
});
// 在文件末尾使用 test 块
test "module tests" {
// 引用当前模块
_ = @import("main.zig");
// 或者单独引用测试文件
_ = @import("tests/tests.zig");
}
test "memory leak detection" {
var gpa: std.heap.DebugAllocator(.{}) = .init;
defer {
const leaked = gpa.deinit();
// leaked 为 true 表示有泄漏
if (leaked) @panic("Memory leak detected!");
}
const allocator = gpa.allocator();
const buf = try allocator.alloc(u8, 100);
// ⚠️ 忘记 allocator.free(buf) 会导致泄漏
// defer allocator.free(buf);
}
test "use testing allocator" {
const allocator = std.testing.allocator;
// testing.allocator 会自动检测泄漏
const buf = try allocator.alloc(u8, 10);
defer allocator.free(buf); // 不 free 会报告泄漏
}
# 测试失败时输出泄漏信息
zig test src/main.zig
# Memory leak detected: 1 allocations remaining (100 bytes)
std.log.debug("debug message: {}", .{value}); // 编译时可用
std.log.info("info: {}", .{value}); // 默认显示
std.log.warn("warning: {}", .{value}); // 重要警告
std.log.err("error: {}", .{value}); // 错误
const log = std.log.scoped(.http_client);
log.info("request to {s}", .{url});
// 输出: [http_client] request to https://example.com
# 设置日志级别(默认 .info)
zig build -Dlog-level=debug
# 或按作用域过滤
zig build -Dlog-scope-override=http_client=debug
// 调试断言(仅在安全模式下检查)
std.debug.assert(x > 0);
// 不可达(标记不可能执行的代码路径)
unreachable;
// 主动 panic
@panic("something went wrong");
// 在 panic 或断言失败时自动打印堆栈
// 手动打印:
std.debug.dumpCurrentStackTrace(null);
const bytes = [_]u8{ 0x48, 0x65, 0x6C, 0x6C, 0x6F };
std.debug.hexDump("data", &bytes);
// 输出:
// data:
// 00000000: 48 65 6C 6C 6F Hello
const tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
const run_tests = b.addRunArtifact(tests);
const test_step = b.step("test", "运行单元测试");
test_step.dependOn(&run_tests.step);
const test_step = b.step("test", "运行所有测试");
for ([_]*std.Build.Module{ mod_a, mod_b, mod_c }) |mod| {
const t = b.addTest(.{ .root_module = mod });
test_step.dependOn(&b.addRunArtifact(t).step);
}
expectEqual 使用 peer type — 两参数必须显式类型一致,推荐 expectEqual(@as(u32, 42), value)testing.allocator 只用于测试 — 它自动检测泄漏,但性能较差,生产环境用 DebugAllocatortest "..." { test "..." {} } 不合法std.log.debug 默认不显示 — 需要在构建时启用 -Dlog-level=debugQ:如何只运行特定的测试?
A:命令行 zig test src/main.zig --test-filter "http",或通过 build.zig 的 filters 选项。
Q:测试依赖的初始化代码怎么写?
A:在 test 块内部初始化,或创建一个全局的测试辅助函数 fn testUtil() !void。
Q:Zig 有基准测试吗?
A:Zig 标准库尚未内置 benchmark 工具。可以在测试中手动计时:const start = std.time.Timer.start()?。