mcpskills.net
SkillsMCPsAgentsPrompts
mcpskills.net — A curated directory of AI agent Skills and MCP servers
TermsPrivacy
← Back to Skills
Backend

zig-testing

Zig 测试与调试技能。涉及 std.testing 的断言、测试组织、内存泄漏检测、以及 std.debug 的日志、堆栈回溯。在需要编写测试、调试代码、诊断问题时调用。

by full-stack-skillsRepository →Source →

Zig 测试与调试

基于 std.testing 和 std.debug 的质量保障工具(Zig 0.16.0)。

Capability Boundaries

✅ 强项

  1. 单元测试编写与断言
  2. 测试组织(test 声明、doctest、测试过滤器)
  3. 内存泄漏检测
  4. 日志输出(std.log)
  5. 调试工具(panic、断言、堆栈回溯、hex dump)

⚠️ 前置要求

  1. 确认 Zig 版本(zig version)

❌ 不适用范围

  1. 构建系统测试配置 → 使用 zig-build-system 技能
  2. 集成测试框架 → 使用 zig-0.16 技能
  3. 性能基准测试 → 暂不涉及(Zig 尚未内置 benchmark)

何时使用

  • "帮我写单元测试"
  • "调试这个函数的输出"
  • "检查内存泄漏"

Data Privacy

本技能不收集、存储或传输任何用户数据。

Workflow — 测试

步骤 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);
}

doctest(文档中的测试)

/// 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");
}

内存泄漏检测

使用 DebugAllocator

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);
}

使用 testing.allocator

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

panic 和断言

// 调试断言(仅在安全模式下检查)
std.debug.assert(x > 0);

// 不可达(标记不可能执行的代码路径)
unreachable;

// 主动 panic
@panic("something went wrong");

堆栈回溯

// 在 panic 或断言失败时自动打印堆栈
// 手动打印:
std.debug.dumpCurrentStackTrace(null);

Hex Dump

const bytes = [_]u8{ 0x48, 0x65, 0x6C, 0x6C, 0x6F };
std.debug.hexDump("data", &bytes);
// 输出:
// data:
// 00000000: 48 65 6C 6C 6F                                Hello

测试配置(build.zig)

标准测试步骤

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);
}

Gotchas

  1. expectEqual 使用 peer type — 两参数必须显式类型一致,推荐 expectEqual(@as(u32, 42), value)
  2. testing.allocator 只用于测试 — 它自动检测泄漏,但性能较差,生产环境用 DebugAllocator
  3. test 声明不能嵌套 — test "..." { test "..." {} } 不合法
  4. doctest 只验证不输出 — 文档中的代码块默认被测试,但如果 panic 不会显示详细信息
  5. std.log.debug 默认不显示 — 需要在构建时启用 -Dlog-level=debug

FAQ

Q:如何只运行特定的测试? 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()?。