zig-debugging-tests
Some patterns I have started to use when writing zig code with unit tests.
Introduction
Although I try to make good use of the debugger, I am quite used to print-based debugging, especially for unit tests. However, one big problem with using debug print for debugging, is that the debug printing sometimes generates a lot of noise. If I am running something in a loop, and only one iteration of the loop produces the error, every iteration produces the full set of output.
Thanks to Zig's errdefer
, I found a neat trick that really helps with this!
errdefer in tests
Zig using errors
, instead of panics like rust unit tests, allows the programmer
to use errdefer
to print something only when a test actually fails.
While the std.testing.expect
family of functions do a decent job of printing
the output, sometimes I just need more context. For example, when testing a gap
buffer, I might want to see the contents of the gap buffer at the failing test,
and some extra stats about the gap buffer.
Instead of printing the gap buffer manually at various interesting points, I find that doing:
errdefer std.debug.print("{}", .{gap_buffer});
Does a fantastic job of avoiding cluttering the code.
Running tests in the debugger
If anything more complex is necessary, using the debugger is the way to go.
However, naively trying to run seergdb
or gdb -tui
directly from the
terminal gets difficult, as the test binaries are not in zig-out
directory
(understandably) but in the zig-cache
directory.
I learned a trick from ziggit that the build.zig
file can run commands,
and you can feed the artifact path of a command as an argument into the command:
// seergdb is a gdb gui frontend
const debugger = b.addSystemCommand(&.{ "seergdb", "--run", "--" });
debugger.addArtifactArg(exe_unit_tests);
const debug_step = b.step("debug", "Run unit tests under debugger");
debug_step.dependOn(&debugger.step);
This makes it really easy to run the proper binary; however, this won't always
stop execution for test errors, so it may necessitate adding some @breakpoint
calls.