Testing
23.1 Test Blocks
Test blocks are stripped from non-test builds. Tests run in parallel by the build system.
const std = @import("std");
const testing = std.testing;
fn add(a: i32, b: i32) i32 { return a + b; }
test "add works" {
try testing.expect(add(2, 3) == 5);
try testing.expectEqual(@as(i32, 5), add(2, 3));
}
test "strings and slices" {
try testing.expectEqualStrings("hello", "hello");
try testing.expectEqualSlices(u8, &.{ 1, 2 }, &.{ 1, 2 });
try testing.expectStringStartsWith("hello", "he");
}
test "errors" {
try testing.expectError(error.InvalidChar, parseDigit('x'));
}
test "no leaks with testing.allocator" {
const alloc = testing.allocator; // fails the test on leaks
var list: std.ArrayList(u8) = .empty;
defer list.deinit(alloc);
try list.append(alloc, 1);
try testing.expect(list.items.len == 1);
}
test "approximate floats" {
try testing.expectApproxEqAbs(@as(f64, 0.3), 0.1 + 0.2, 1e-9);
}
test "skip" {
if (@import("builtin").os.tag == .windows) return error.SkipZigTest;
}
test add { // doctest: a test named after a decl (shows in docs)
try testing.expect(add(1, 1) == 2);
}zig test src/main.zig
zig test src/main.zig --test-filter "add"
zig build test
zig build test --summary all23.2 Testing Allocation Failures
std.testing.FailingAllocator fails after N allocations, which verifies errdefer cleanup paths.
test "handles OOM" {
try testing.checkAllAllocationFailures(testing.allocator, functionUnderTest, .{arg});
}23.3 Fuzz Testing (0.14+, Integrated)
test "fuzz parser" {
try std.testing.fuzz({}, struct {
fn testOne(_: void, input: []const u8) anyerror!void {
_ = parse(input) catch {};
}
}.testOne, .{});
}zig build test --fuzz # coverage-guided fuzzing with a web UI23.4 Test Organization
Put unit tests next to the code in the same file. Use refAllDecls in root files. Put integration tests in separate files added as test artifacts in build.zig.
Snapshot testing: the Snaptest/ohsnap packages. Benchmarks: zBench or a manual std.time.Timer.