# Tests

### Tests

Zig has tests in the language.

A test is written with the `test` keyword:

```zig
const std = @import("std");

fn add(a: i32, b: i32) i32 {
    return a + b;
}

test "add two numbers" {
    try std.testing.expect(add(2, 3) == 5);
}
```

Run it directly:

```sh
zig test src/main.zig
```

In a project, tests are usually run through `zig build`.

A test step looks like this:

```zig
const tests = b.addTest(.{
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    }),
});

const run_tests = b.addRunArtifact(tests);

const test_step = b.step("test", "Run tests");
test_step.dependOn(&run_tests.step);
```

Now run:

```sh
zig build test
```

The build file compiles the tests, then runs the test executable.

A test block may appear beside the code it checks:

```zig
fn isDigit(c: u8) bool {
    return c >= '0' and c <= '9';
}

test "isDigit" {
    try std.testing.expect(isDigit('0'));
    try std.testing.expect(isDigit('9'));
    try std.testing.expect(!isDigit('a'));
}
```

This is the common style in Zig. Small tests stay near the function. Larger tests can go in separate files.

The `std.testing` namespace provides helpers:

```zig
try std.testing.expect(value);
try std.testing.expectEqual(expected, actual);
try std.testing.expectError(error.NotFound, result);
```

Use `expect` for boolean conditions.

```zig
try std.testing.expect(x > 0);
```

Use `expectEqual` when comparing values.

```zig
try std.testing.expectEqual(@as(u32, 42), value);
```

The explicit type is often useful. It prevents confusion between integer types.

Tests can allocate memory. Use the testing allocator:

```zig
test "array list" {
    var list = std.ArrayList(u8).init(std.testing.allocator);
    defer list.deinit();

    try list.append('a');
    try list.append('b');

    try std.testing.expectEqual(@as(usize, 2), list.items.len);
}
```

The testing allocator checks for leaks. If the test forgets to release memory, the test fails.

This is deliberate. In Zig, allocation is explicit, so tests should check that cleanup is also explicit.

A test can return an error. That is why calls often use `try`.

```zig
test "fallible operation" {
    try mayFail();
}
```

If `mayFail` returns an error, the test fails.

Files can contain many tests:

```zig
test "empty input" {
    // ...
}

test "one item" {
    // ...
}

test "many items" {
    // ...
}
```

Test names should describe the case being checked. They are not function names. They are messages for the reader.

A library often has one test step for the root file:

```zig
const lib_tests = b.addTest(.{
    .root_module = lib.root_module,
});
```

An executable may have tests too, but serious projects usually move reusable logic into modules that can be tested without running the program.

A build file may combine several test binaries under one command:

```zig
const test_step = b.step("test", "Run all tests");

const unit_tests = b.addTest(.{
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    }),
});
test_step.dependOn(&b.addRunArtifact(unit_tests).step);

const cli_tests = b.addTest(.{
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    }),
});
test_step.dependOn(&b.addRunArtifact(cli_tests).step);
```

Now one command runs both:

```sh
zig build test
```

Testing in Zig is plain. There is no separate test language. A test is a block of Zig code. It imports the same modules, uses the same allocator rules, and returns errors in the same way as ordinary code.

Exercise 15-17. Add a test block for a function that returns the larger of two integers.

Exercise 15-18. Use `std.testing.expectEqual` instead of `expect`.

Exercise 15-19. Write a test that allocates an `ArrayList` and releases it.

Exercise 15-20. Add a `test` step to `build.zig`.

