I am a newcomer to Zig (using 0.15.dev). The pattern is work in progress and may not be optimal by design, or may even contain incorrect assumptions, or not applicable to the version you use. I however struggled with some elementary issues resulting in me sharing this in the hope that it will assist somebody that have the same issues:
- How to run a test, in a module, that uses types from a different module… The key being that without going through the build (build.zig), it cannot resolve the needed modules.
- Filtering and running tests selectively
- A reasonable way to get started on structuring modules and tests into files - specifically to have an assembly file which exposes the test files and cases for a module.
Thanks to @castholm on thread How to filter test using --test-filter 'test-name' in conjunction with build.zig - #2 by pierrelgol.
Also note that while I copied snippets I manually changed some sensitive references. So the source compiles may have a typo (or two).
Shell
# Run one test
zig build test -Dmytest="Arbitrary Test"
# Run two tests
zig build test -Dmytest="Arbitrary Test" -Dmytest="Test Client"
# Filters seem to be specific by name (at this point)
# SO THE FOLLOWING DOES NOT RESOLVE "Arbitrary Test".. will investigate still
zig build test -Dmytest="Arbitrary"
zig build test -Dmytest="Arbitrary*"
zig build test -Dmytest="Arbitrary.*"
# Run all tests
zig build test
Partial build.zig
// Build the test step...
const run_lib_unit_tests = addTest(
b,
utils_module,
target,
optimize,
);
// Important!
// The filter name for the test "assembly" being "mytest"
// The assembly "root" being ".../assemble_tests.zig"
// The module import of utils to the test, which itself is module math
// I DO NOT ADVOCATE CALLING A MODULE DIRECTORY _module. This is simply
// for the example._
fn addTest(
b: *std.Build,
utils_module: *std.Build.Module,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
) *std.Build.Step.Run {
const f: []const []const u8 = b.option(
[]const []const u8,
"mytest", // <- FILTER NAME
"Description",
) orelse &.{};
const tst = b.addTest(.{
.root_source_file = b.path("src/protocol/math_module/assemble_tests.zig"),
.filters = f,
.target = target,
.optimize = optimize,
});
tst.root_module.addImport(utils_module_name, utils_module);
return b.addRunArtifact(tst);
}
src/protocol/math_module/assemble_tests.zig
const std = @import("std");
// The tests are actually in here
pub const t1 = @import("tests1.zig");
test {
// THIS IS THE MAGIC THAT EXPOSES ALL @imported TESTS TO the build.zig via
// The .root_source_file in build.zig!
std.testing.refAllDecls(@This());
}
src/protocol/math_module/tests1.zig
const std = @import("std");
const utils = @import("utils");
const eq = std.testing.expectEqual;
test "Test Client" {
// ...test code
}
test "Arbitrary Test" {
// ...test code
}