# Какие дополнительные приёмы тестирования существуют в Zig?

В 
Опубликовано 2025-09-19

Кроме классических тестов на правильность функционирования, в Zig доступно несколько полезных приёмов, позволяющих повысить уверенность в работоспособности вашего кода:

# 1. Параметризированные тесты

Параметризированные тесты позволяют проводить серию проверок одной и той же функции с различными наборами значений. Они полезны, когда необходимо убедиться, что функция стабильно работает с множеством комбинаций аргументов.

Например, предположим, что у вас есть функция, преобразующая температуру из Цельсия в Фаренгейты:

// src/converter.zig
const std = @import("std");

pub fn celsiusToFahrenheit(celsius: f32) f32 {
    return celsius * 9 / 5 + 32;
}

Тогда в тестах можно применить параметризацию:

// tests/test_converter.zig
const std = @import("std");
const converter = @import("converter");

test "Преобразование температуры" {
    inline for ([_][2]f32{
        .{0, 32}, // Входящее значение и ожидаемое выходящее
        .{100, 212},
        .{-40, -40},
    }) |pair| {
        const celsius = pair[0];
        const expected = pair[1];
        const result = converter.celsiusToFahrenheit(celsius);
        try std.testing.expectApproxEqAbs(expected, result, 0.01);
    }
}

Использование цикла inline for позволяет перебирать пары значений и сравнивать результат с ожиданием.

# 2. Тестирование ошибок

Многие функции в Zig возвращают ошибки (error), и важно уметь их проверять. Для этого служит оператор try, позволяющий перехватывать ошибки.

Допустим, у вас есть функция чтения файла, которая возвращает ошибку, если файл отсутствует:

// src/file_io.zig
const std = @import("std");

pub fn readFile(file_path: []const u8) ![]const u8 {
    const file = try std.fs.openFileAbsolute(file_path, .{});
    defer file.close();
    return file.readToEndAlloc(std.testing.allocator, 1024);
}

В тестах можно проверять возникновение ожидаемой ошибки:

// tests/test_file_io.zig
const std = @import("std");
const file_io = @import("file_io");

test "Ошибка при чтении отсутствующего файла" {
    const err = file_io.readFile("/path/to/nonexistent.file") catch |e| e;
    try std.testing.expect(err == error.FileNotFound);
}

# 3. Ассертивные ожидания

Иногда приходится проверять сложное состояние, например, свойства массива или сложной структуры. Для этого предусмотрены специальные функции сравнения:

  • std.testing.expectEqual — проверка точного совпадения значений.
  • std.testing.expectEqualStrings — сравнение строк.
  • std.testing.expectCloseAbs — проверка близости численных значений с заданной точностью.

Пример проверки численного результата с заданной погрешностью:

test "Корень квадратный из 2 примерно равен 1.414" {
    const sqrt_two: f32 = std.math.sqrt(2.0);
    try std.testing.expectApproxEqAbs(sqrt_two, 1.414, 0.001);
}

# 4. Тестирование на нескольких архитектурах

Одним из преимуществ Zig является возможность кросс-платформенного тестирования. Вы можете протестировать код на разных архитектурах и ОС, используя возможности целевых платформ.

Например, следующий скрипт запускает тесты на трёх разных платформах:

// build.zig
const std = @import("std");

pub fn build(b: *std.Build) void {
    const targets = [_]std.zig.CrossTarget{
        .{},
        .{ .cpu_arch = .x86_64, .os_tag = .linux },
        .{ .cpu_arch = .arm, .os_tag = .ios },
    };

	const optimize = b.standardOptimizeOption(.{});

    const test_step = b.step("test-all-targets", "Запустить тесты на всех платформах");

    for (targets) |target| {
        const lib = b.addTest(.{
            .root_module = b.createModule(.{
                .root_source_file = b.path("tests/test_main.zig"),
                .target = target,
				.optimize = optimize,
            }),
        });
		const run_tests = b.addRunArtifact(lib);
        test_step.dependOn(&run_tests.step);
    }
}

Теперь команда zig build test-all-targets запускает тесты на каждой указанной платформе.

# Заключение

Правильно составленные тесты являются основой качественной разработки на любом языке программирования, включая Zig. Использование рассмотренных приёмов поможет увеличить покрытие тестов, сократить число возможных дефектов и ускорить выявление проблем. Главное правило — каждый компонент должен быть покрыт соответствующими тестами, а сами тесты должны оставаться лёгкими для понимания и модификации.