SuperAPI AI Directory

zig-testing

Testing & quality

View repository

Updated 10-15 21:48

About this skill

Zig Testing and Debugging

Quality assurance tools based on std.testing and std.debug (Zig 0.16.0).

Capability Boundaries

✅ Strengths

  1. Writing unit tests and assertions
  2. Test organization (test declarations, doctests, test filters)
  3. Memory leak detection
  4. Log output (std.log)
  5. Debugging tools (panic, assertions, stack traces, hex dump)

⚠️ Prerequisites

  1. Confirm the Zig version (zig version)

❌ Out of Scope

  1. Build system test configuration → use the zig-build-system skill
  2. Integration testing frameworks → use the zig-0.16 skill
  3. Performance benchmarking → not covered for now (Zig does not yet have a built-in benchmark)

When to Use

  • "Help me write unit tests"
  • "Debug the output of this function"
  • "Check for memory leaks"

Data Privacy

This skill does not collect, store, or transmit any user data.

Workflow — Testing

Step 1. Declare the test — test "name" { ... } Step 2. Use assertions — expect, expectEqual, expectEqualStrings Step 3. Run the tests — zig test src/main.zig or zig build test Step 4. Check the results — pass/fail/leak

Assertion Quick Reference

Assertion Purpose
expect(bool) The condition is true
expectEqual(expected, actual) Shallow equality (peer type)
expectEqualDeep(expected, actual) Deep equality (recursive comparison)
expectEqualStrings(expected, actual) String equality (with diff)
expectEqualSlices(T, expected, actual) Slice equality
expectError(error, result) Returns a specific error
expectApproxEqAbs(expected, actual, eps) Floating-point approximation (absolute error)
expectApproxEqRel(expected, actual, eps) Floating-point approximation (relative error)
expectFmt(expected, template, args) Formatted output matches
expectStringStartsWith(actual, prefix) String prefix
expectStringEndsWith(actual, suffix) String suffix

Basic Assertions

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

Floating-Point Comparison

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

Error Checking

test "error handling" {
    const result: anyerror!i32 = error.SomeError;
    try std.testing.expectError(error.SomeError, result);
}

Test Organization

Inline Tests

const std = @import("std");
const expect = std.testing.expect;

test "inline test" {
    try expect(1 + 1 == 2);
}

doctest (tests in documentation)

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

Test Filters

# 运行名称包含 "http" 的测试
zig test src/main.zig --test-filter "http"

# 在 build.zig 中过滤
const tests = b.addTest(.{
    .root_module = mod,
    .filters = &.{"specific_test"},
});

Test Modules

// 在文件末尾使用 test 块
test "module tests" {
    // 引用当前模块
    _ = @import("main.zig");
    // 或者单独引用测试文件
    _ = @import("tests/tests.zig");
}

Memory Leak Detection

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

Using 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 会报告泄漏
}

Detection Logs

# 测试失败时输出泄漏信息
zig test src/main.zig
# Memory leak detected: 1 allocations remaining (100 bytes)

Logging and Debugging

Leveled Logging

std.log.debug("debug message: {}", .{value});    // 编译时可用
std.log.info("info: {}", .{value});              // 默认显示
std.log.warn("warning: {}", .{value});           // 重要警告
std.log.err("error: {}", .{value});              // 错误

Custom Log Scopes

const log = std.log.scoped(.http_client);
log.info("request to {s}", .{url});
// 输出: [http_client] request to https://example.com

Runtime Log Levels

# 设置日志级别(默认 .info)
zig build -Dlog-level=debug
# 或按作用域过滤
zig build -Dlog-scope-override=http_client=debug

panic and Assertions

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

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

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

Stack Traces

// 在 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

Test Configuration (build.zig)

Standard Test Step

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

Multi-Module Test Aggregation

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 Use peer type — the two parameters must have explicitly matching types; recommended expectEqual(@as(u32, 42), value)
  2. testing.allocator is only for testing — it automatically detects leaks, but performance is poor; in production use DebugAllocator
  3. test declarations cannot be nested — test "..." { test "..." {} } is invalid
  4. doctests only verify and do not output — code blocks in documentation are tested by default, but if they panic, detailed information is not displayed
  5. std.log.debug is not displayed by default — it needs to be enabled at build time -Dlog-level=debug

FAQ

Q: How do I run only specific tests? A: Command line zig test src/main.zig --test-filter "http", or via build.zig's filters option.

Q: How do I write the initialization code that the tests depend on? A: Initialize inside the test block, or create a global test helper function fn testUtil() !void。

Q: Does Zig have benchmarks? A: The Zig standard library does not yet have a built-in benchmark tool. You can time it manually in tests:const start = std.time.Timer.start()?。