Running Tests
A test block is a language construct, not a framework. No imports, no
registration, no annotations.
const std = @import("std");
const expect = std.testing.expect;
fn add(a: i32, b: i32) i32 {
return a + b;
}
test "a test is just a named block" {
try expect(add(2, 2) == 4);
}
test "expectEqual reports both values on failure" {
try std.testing.expectEqual(@as(i32, 4), add(2, 2));
}
test "comparing slices" {
try std.testing.expectEqualStrings("abc", "ab" ++ "c");
try std.testing.expectEqualSlices(u8, &[_]u8{ 1, 2 }, &[_]u8{ 1, 2 });
}
test "asserting an error is returned" {
const failing = struct {
fn f() error{Nope}!void {
return error.Nope;
}
}.f;
try std.testing.expectError(error.Nope, failing());
}
test "the testing allocator fails the test on a leak" {
const gpa = std.testing.allocator;
const buf = try gpa.alloc(u8, 10);
defer gpa.free(buf); // remove this line and the test fails
try expect(buf.len == 10);
}
test "skipping" {
if (@import("builtin").cpu.arch != .wasm32) return error.SkipZigTest;
try expect(true);
}Running them
zig test file.zig # just this file
zig build test # the test step of a build.zig
zig test file.zig --test-filter "name"
Tests in a file only run if that file is the test root or is reachable from it
via @import. A test in a module nobody imports never runs, which is worth
knowing when a test you expected to fail stays quiet.
The assertion helpers
| Helper | Use |
|---|---|
expect(bool) | general condition |
expectEqual(a, b) | prints both values on failure |
expectEqualStrings | string comparison with a readable diff |
expectEqualSlices(T, a, b) | slice comparison |
expectError(err, expr) | asserts a specific error |
Prefer expectEqual over expect(a == b): when it fails, it tells you what
the values actually were.
Leak detection is on by default
std.testing.allocator fails the test if anything it allocated was not freed.
This is not an optional tool you remember to run. Every test that allocates is
a leak test:
const buf = try std.testing.allocator.alloc(u8, 10);
defer std.testing.allocator.free(buf); // omit this and the test fails
Skipping
return error.SkipZigTest marks a test skipped rather than failed. It is the
way to handle a test that only applies to some targets.
These pages are the tests
Every snippet in this guide is compiled and run by CI, and the test ones
report through this same runner. The output you see when you press Run is the
real zig test output, executed in your browser as WebAssembly.