Zig Test Helpers
A test helper is a plain function that test blocks share, so repeated checking lives in one place. Helpers keep tests short and keep the same check identical everywhere.
One shared number check
Two blocks share one helper for doubling. The helper holds the assertion, and each block passes different inputs.
const std = @import("std");
fn double(n: i32) i32 {
return n * 2;
}
fn checkDouble(input: i32, expected: i32) !void {
try std.testing.expectEqual(expected, double(input));
}
test "double small" {
try checkDouble(3, 6);
}
test "double large" {
try checkDouble(20, 40);
}One shared string check
String checks share a helper in the same way. The helper compares the real string with the expected string.
const std = @import("std");
fn greeting() []const u8 {
return "hello, zig";
}
fn farewell() []const u8 {
return "goodbye, zig";
}
fn checkGreeting(actual: []const u8, expected: []const u8) !void {
try std.testing.expectEqualStrings(expected, actual);
}
test "greeting matches" {
try checkGreeting(greeting(), "hello, zig");
}
test "farewell matches" {
try checkGreeting(farewell(), "goodbye, zig");
}One shared error check
Error checks can share a helper too. Here one helper names the error for two different inputs.
const std = @import("std");
const CheckError = error{ TooSmall, TooBig };
fn check(n: i32) CheckError!i32 {
if (n < 0) return error.TooSmall;
if (n > 10) return error.TooBig;
return n * 2;
}
fn checkTooSmall(input: i32) !void {
try std.testing.expectError(error.TooSmall, check(input));
}
test "negative fails" {
try checkTooSmall(-1);
}
test "large negative fails" {
try checkTooSmall(-50);
}
test "zero succeeds" {
try std.testing.expectEqual(@as(i32, 0), try check(0));
}Example
const std = @import("std");
fn double(n: i32) i32 {
return n * 2;
}
fn greeting() []const u8 {
return "hello, zig";
}
fn farewell() []const u8 {
return "goodbye, zig";
}
fn checkDouble(input: i32, expected: i32) !void {
try std.testing.expectEqual(expected, double(input));
}
fn checkGreeting(actual: []const u8, expected: []const u8) !void {
try std.testing.expectEqualStrings(expected, actual);
}
test "double small" {
try checkDouble(3, 6);
}
test "double large" {
try checkDouble(20, 40);
}
test "greeting matches" {
try checkGreeting(greeting(), "hello, zig");
}
test "farewell matches" {
try checkGreeting(farewell(), "goodbye, zig");
}Key points
- Test helper: a test helper is a plain function that several test blocks call instead of repeating the same code.
- A helper is an ordinary function, not a test block, so Zig does not run it as a test on its own.
- Pass the values to check into the helper, and let the helper run the assertion.
- A helper that can return an error lets a failed assertion fail the calling test.
- Keep helpers small and named for one job, so a failure still points at one idea.
- Do not put test blocks inside helpers. Keep the test blocks separate and let them call the helper.
This run uses two helpers, one for numbers and one for strings. Each test block is a single call to a helper, so the tests stay short. The helpers hold the assertions, while the blocks supply the inputs.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What is a test helper?