- zig test is a tool that can be used to quickly build and run Zig code
- to make sure behavior meets expectations. {#syntax#}@import("builtin").is_test{#endsyntax#}
- is available for code to detect whether the current build is a test build.
-
- Zig has lazy top level declaration analysis, which means that if a function is not called,
- or otherwise used, it is not analyzed. This means that there may be an undiscovered
- compile error in a function because it is never called.
-
- Note that, while in {#link|Debug#} and {#link|ReleaseSafe#} modes, {#link|unreachable#} emits a
- call to {#link|@panic#}, in {#link|ReleaseFast#} and {#link|ReleaseSmall#} modes, it is really
- undefined behavior. The implementation of {#syntax#}std.debug.assert{#endsyntax#} is as
- simple as:
-
- This means that when testing in ReleaseFast or ReleaseSmall mode, {#syntax#}assert{#endsyntax#}
- is not sufficient to check the result of a computation:
-
- When compiling this test in {#link|ReleaseFast#} mode, it invokes unchecked
- {#link|Undefined Behavior#}. Since that could do anything, this documentation
- cannot show you the output.
-
-
- Better practice for checking the output when testing is to use {#syntax#}std.testing.expect{#endsyntax#}:
-
- {#code_begin|test_err|test "expect in release fast mode"... FAIL (TestUnexpectedResult)#}
- {#code_release_fast#}
-const std = @import("std");
-const expect = std.testing.expect;
-
-test "expect in release fast mode" {
- try expect(false);
-}
- {#code_end#}
-
See the rest of the {#syntax#}std.testing{#endsyntax#} namespace for more available functions.
-
- zig test has a few command line parameters which affect the compilation. See
- zig --help for a full list. The most interesting one is --test-filter [text].
- This makes the test build only include tests whose name contains the supplied filter text.
- Again, thanks to lazy analysis, this can allow you to narrow a build to only a few functions in
- isolation.
-
- {#header_close#}
{#header_open|Comments#}
- {#code_begin|test|comments#}
-const expect = @import("std").testing.expect;
+ {#code_begin|exe|comments#}
+const print = @import("std").debug.print;
-test "comments" {
+pub fn main() void {
// Comments in Zig start with "//" and end at the next LF byte (end of line).
- // The below line is a comment, and won't be executed.
+ // The line below is a comment and won't be executed.
- //expect(false);
+ //print("Hello?", .{});
- const x = true; // another comment
- try expect(x);
+ print("Hello, world!\n", .{}); // another comment
}
{#code_end#}
@@ -896,24 +820,25 @@ pub fn main() void {
in recent versions of the Unicode specification (as of Unicode 13.0).
In Zig, a Unicode code point literal corresponds to the Unicode definition of a code point.
@@ -1047,6 +972,291 @@ test "init with undefined" {
{#header_close#}
{#header_close#}
{#header_close#}
+ {#header_open|Zig Test#}
+
+ Code written within one or more {#syntax#}test{#endsyntax#} declarations can be used to ensure behavior meets expectations:
+
+ {#code_begin|test|introducing_zig_test#}
+const std = @import("std");
+
+test "expect addOne adds one to 41" {
+
+ // The Standard Library contains useful functions to help create tests.
+ // `expect` is a function that verifies its argument is true.
+ // It will return an error if its argument is false to indicate a failure.
+ // `try` is used to return an error to the test runner to notify it that the test failed.
+ try std.testing.expect(addOne(41) == 42);
+}
+
+/// The function `addOne` adds one to the number given as its argument.
+fn addOne(number: i32) i32 {
+ return number + 1;
+}
+ {#code_end#}
+
+ The introducing_zig_test.zig code sample tests the {#link|function|Functions#}
+ {#syntax#}addOne{#endsyntax#} to ensure that it returns {#syntax#}42{#endsyntax#} given the input
+ {#syntax#}41{#endsyntax#}. From this test's perspective, the {#syntax#}addOne{#endsyntax#} function is
+ said to be code under test.
+
+
+ zig test is a tool that creates and runs a test build. By default, it builds and runs an
+ executable program using the default test runner provided by the {#link|Zig Standard Library#}
+ as its main entry point. During the build, {#syntax#}test{#endsyntax#} declarations found while
+ {#link|resolving|Root Source File#} the given Zig source file are included for the default test runner
+ to run and report on.
+
+
+
+ The shell output shown above displays two lines after the zig test command. These lines are
+ printed to standard error by the default test runner:
+
+
+
Test [1/1] test "expect addOne adds one to 41"...
+
Lines like this indicate which test, out of the total number of tests, is being run.
+ In this case, [1/1] indicates that the first test, out of a total of
+ one test, is being run. Note that, when the test runner program's standard error is output
+ to the terminal, these lines are cleared when a test succeeds.
+
+
All 1 tests passed.
+
This line indicates the total number of tests that have passed.
+
+ {#header_open|Test Declarations#}
+
+ Test declarations contain the {#link|keyword|Keyword Reference#} {#syntax#}test{#endsyntax#}, followed by an
+ optional name written as a {#link|string literal|String Literals and Unicode Code Point Literals#}, followed
+ by a {#link|block|blocks#} containing any valid Zig code that is allowed in a {#link|function|Functions#}.
+
+
+
+ Test declarations are similar to {#link|Functions#}: they have a return type and a block of code. The implicit
+ return type of {#syntax#}test{#endsyntax#} is the {#link|Error Union Type#} {#syntax#}anyerror!void{#endsyntax#},
+ and it cannot be changed. When a Zig source file is not built using the zig test tool, the test
+ declarations are omitted from the build.
+
+
+ Test declarations can be written in the same file, where code under test is written, or in a separate Zig source file.
+ Since test declarations are top-level declarations, they are order-independent and can
+ be written before or after the code under test.
+
+ When the zig test tool is building a test runner, only resolved {#syntax#}test{#endsyntax#}
+ declarations are included in the build. Initially, only the given Zig source file's top-level
+ declarations are resolved. Unless nested containers are referenced from a top-level test declaration,
+ nested container tests will not be resolved.
+
+
+ The code sample below uses the {#syntax#}std.testing.refAllDecls(@This()){#endsyntax#} function call to
+ reference all of the containers that are in the file including the imported Zig source file. The code
+ sample also shows an alternative way to reference containers using the {#syntax#}_ = C;{#endsyntax#}
+ syntax. This syntax tells the compiler to ignore the result of the expression on the right side of the
+ assignment operator.
+
+ {#code_begin|test|testdecl_container_top_level#}
+const std = @import("std");
+const expect = std.testing.expect;
+
+// Imported source file tests will run when referenced from a top-level test declaration.
+// The next line alone does not cause "introducing_zig_test.zig" tests to run.
+const imported_file = @import("introducing_zig_test.zig");
+
+test {
+ // To run nested container tests, either, call `refAllDecls` which will
+ // reference all declarations located in the given argument.
+ // `@This()` is a builtin function that returns the innermost container it is called from.
+ // In this example, the innermost container is this file (implicitly a struct).
+ std.testing.refAllDecls(@This());
+
+ // or, reference each container individually from a top-level test declaration.
+ // The `_ = C;` syntax is a no-op reference to the identifier `C`.
+ _ = S;
+ _ = U;
+ _ = @import("introducing_zig_test.zig");
+}
+
+const S = struct {
+ test "S demo test" {
+ try expect(true);
+ }
+
+ const SE = enum {
+ V,
+
+ // This test won't run because its container (SE) is not referenced.
+ test "This Test Won't Run" {
+ try expect(false);
+ }
+ };
+};
+
+const U = union { // U is referenced by the file's top-level test declaration
+ s: US, // and US is referenced here; therefore, "U.Us demo test" will run
+
+ const US = struct {
+ test "U.US demo test" {
+ // This test is a top-level test declaration for the struct.
+ // The struct is nested (declared) inside of a union.
+ try expect(true);
+ }
+ };
+
+ test "U demo test" {
+ try expect(true);
+ }
+};
+ {#code_end#}
+ {#header_close#}
+ {#header_open|Test Failure#}
+
+ The default test runner checks for an {#link|error|Errors#} returned from a test.
+ When a test returns an error, the test is considered a failure and its {#link|error return trace|Error Return Traces#}
+ is output to standard error. The total number of failures will be reported after all tests have run.
+
+ {#code_begin|test_err#}
+const std = @import("std");
+
+test "expect this to fail" {
+ try std.testing.expect(false);
+}
+
+test "expect this to succeed" {
+ try std.testing.expect(true);
+}
+ {#code_end#}
+ {#header_close#}
+ {#header_open|Skip Tests#}
+
+ One way to skip tests is to filter them out by using the zig test command line parameter
+ --test-filter [text]. This makes the test build only include tests whose name contains the
+ supplied filter text. Note that non-named tests are run even when using the --test-filter [text]
+ command line parameter.
+
+
+ To programmatically skip a test, make a {#syntax#}test{#endsyntax#} return the error
+ {#syntax#}error.SkipZigTest{#endsyntax#} and the default test runner will consider the test as being skipped.
+ The total number of skipped tests will be reported after all tests have run.
+
+ {#code_begin|test#}
+test "this will be skipped" {
+ return error.SkipZigTest;
+}
+ {#code_end#}
+
+ The default test runner skips tests containing a {#link|suspend point|Async Functions#} while the
+ test is running using the default, blocking IO mode.
+ (The evented IO mode is enabled using the --test-evented-io command line parameter.)
+
+ In the code sample above, the test would not be skipped in blocking IO mode if the {#syntax#}nosuspend{#endsyntax#}
+ keyword was used (see {#link|Async and Await#}).
+
+ When code allocates {#link|Memory#} using the {#link|Zig Standard Library#}'s testing allocator,
+ {#syntax#}std.testing.allocator{#endsyntax#}, the default test runner will report any leaks that are
+ found from using the testing allocator:
+
+ The Zig Standard Library's testing namespace contains useful functions to help
+ you create tests. In addition to the expect function, this document uses a couple of more functions
+ as exemplified here:
+
+ {#code_begin|test|testing_functions#}
+const std = @import("std");
+
+test "expectEqual demo" {
+ const expected: i32 = 42;
+ const actual = 42;
+
+ // The first argument to `expectEqual` is the known, expected, result.
+ // The second argument is the result of some expression.
+ // The actual's type is casted to the type of expected.
+ try std.testing.expectEqual(expected, actual);
+}
+
+test "expectError demo" {
+ const expected_error = error.DemoError;
+ const actual_error_union: anyerror!void = error.DemoError;
+
+ // `expectError` will fail when the actual error is different than
+ // the expected error.
+ try std.testing.expectError(expected_error, actual_error_union);
+}
+ {#code_end#}
+
The Zig Standard Library also contains functions to compare {#link|Slices#}, strings, and more. See the rest of the
+ {#syntax#}std.testing{#endsyntax#} namespace in the {#link|Zig Standard Library#} for more available functions.