How to print to stdout when running tests in zig?

1.3k Views Asked by At

When running zig test for something like (example from here)

const std = @import("std");

fn failingFunction() error{Oops}!void {
    return error.Oops;
}

test "returning an error" {
    failingFunction() catch |err| {
        try std.testing.expect(err == error.Oops);
        std.debug.print("return from catched error: {}", .{err});
        return;
    };
}

The output to the console is messed up like

Test [3/6] test.returning an error...All 6 tests passed.

as both std.debug.print and the test runner print to stderr.

I can see why you wouldn't want to have print-outs in library tests, at least not in something you ship to others. However, my experience is that sometimes, this can be useful while you develop the library. According to this post on reddit and this issue on github the described behavior seems ...somehow intended? The docs just tell me that "The default test runner and the Zig Standard Library's testing namespace output messages to standard error.", not that I have to avoid print in tests. So, is there a way to have "clean" printing to stdout while running tests?


zig version
0.12.0-dev.1298+da06269d7
2

There are 2 best solutions below

0
On

Edit 2024-02-19: after diving deeper into Zig, here's a couple of thing I found useful:

  • be careful with print calls in tested code and tests in general. Tests are run in parallel (multi-threaded), so this can cause crashes due to race conditions. If you can't hold back on printing, at least remove anything not absolutely needed ;-)
  • in tests, remember to put sufficient newline characters in the formatting string. Otherwise, things get swallowed e.g. by error output from the compiler.
  • you can also define your own test runner, which gives you some customization options for what is being printed to the console during tests. example.
  • have a look at std.log (overview)- especially scoped logging can be very helpful, for example since you immediately know from where the message is coming
0
On

The Zig testing library uses the Progress utility (https://github.com/ziglang/zig/blob/master/lib/std/Progress.zig) to emit output. This will generate a line of content without a newline, then when a new message is ready to be emitted, it just clears to the beginning of the line and writes the new message. The "clear" step will clear any messages you've emitted on that line too.

You can use at least one newline to "end" your update, and prevent Progress from overwriting your content. Optionally lead with a newline to start your update on its own line too:

        std.log.warn("\nreturn from caught error: {}\n", .{err});