Teste Falha em Zig — Resolver Problemas com Testes

Teste Falha em Zig — Resolver Problemas com Testes

Zig tem um framework de testes integrado que é poderoso e direto. Quando testes falham, este guia ajuda a diagnosticar e resolver os problemas.

Teste Falhando com “expected X, found Y”

Causa: A asserção expect detectou um valor diferente do esperado.

const std = @import("std");
const expect = std.testing.expect;

test "meu teste" {
    const resultado = calcular(2, 3);
    // Se resultado != 5, falha com mensagem
    try expect(resultado == 5);

    // Para mensagem mais descritiva:
    try std.testing.expectEqual(@as(i32, 5), resultado);

    // Para comparar slices/strings:
    try std.testing.expectEqualStrings("esperado", resultado_str);

    // Para comparar slices de bytes:
    try std.testing.expectEqualSlices(u8, &expected, &actual);
}

Dica: Use expectEqual em vez de expect para mensagens de erro mais claras que mostram os valores esperado e encontrado.

Teste Falhando com Memory Leak

Causa: std.testing.allocator detecta memória não liberada.

test "sem leak" {
    const allocator = std.testing.allocator;

    // FALHA: leak detectado
    const dados = try allocator.alloc(u8, 100);
    _ = dados;
    // Faltou: defer allocator.free(dados);

    // CORRETO:
    const dados2 = try allocator.alloc(u8, 100);
    defer allocator.free(dados2);
}

O testing.allocator é rigoroso: qualquer byte não liberado causa falha. Sempre use defer para liberar alocações.

Testes Não São Encontrados

Causa 1: O arquivo com testes não é importado pela árvore de compilação.

// Em src/main.zig — importar módulos que contêm testes
const utils = @import("utils.zig");

// Isso garante que os testes de utils.zig serão encontrados
test {
    @import("utils.zig");
    @import("parser.zig");
    // Importar todos os módulos com testes
}

Causa 2: Usando zig test no arquivo errado.

# Testar arquivo específico
zig test src/utils.zig

# Testar via build system (usa a configuração do build.zig)
zig build test

Filtrar Testes Específicos

# Rodar apenas testes que contêm "parser" no nome
zig build test -- --test-filter "parser"

# Com zig test direto
zig test src/main.zig --test-filter "calcular"

# Exemplo: testar apenas "calcular soma"
zig test src/math.zig --test-filter "calcular soma"

Teste com Timeout

Problema: Teste trava (loop infinito ou deadlock).

# Timeout padrão é generoso — use um limite menor para detectar
# O framework de teste do Zig tem timeout padrão

# Para debugging, use print para ver onde trava
test "não deve travar" {
    std.debug.print("Ponto 1\n", .{});
    // ...código suspeito...
    std.debug.print("Ponto 2\n", .{});
}

Teste de Erro (expect error)

test "deve retornar erro" {
    const resultado = funcaoQueDeveFalhar();

    // Verificar que é um erro específico
    try std.testing.expectError(error.InvalidInput, resultado);
}

test "deve retornar erro genérico" {
    const resultado = funcaoQueDeveFalhar();
    // Verificar que é qualquer erro
    if (resultado) |_| {
        return error.TestUnexpectedResult;
    } else |_| {
        // OK — era erro como esperado
    }
}

Teste com Setup e Teardown

Zig não tem beforeEach/afterEach como outros frameworks. Use funções helper:

const TestContext = struct {
    allocator: std.mem.Allocator,
    db: *Database,

    fn init(allocator: std.mem.Allocator) !TestContext {
        const db = try Database.open(allocator, ":memory:");
        return .{ .allocator = allocator, .db = db };
    }

    fn deinit(self: *TestContext) void {
        self.db.close();
    }
};

test "operação no banco" {
    const allocator = std.testing.allocator;
    var ctx = try TestContext.init(allocator);
    defer ctx.deinit();

    try ctx.db.insert("dados");
    const result = try ctx.db.query("SELECT *");
    try expect(result.len > 0);
}

Teste Falha Apenas em Release Mode

Causa: Código depende de verificações de safety que existem apenas em Debug.

test "comportamento em release" {
    // Este teste pode ter comportamento diferente em Release
    // porque bounds checking e overflow detection são removidos

    // SOLUÇÃO: Não dependa de panics de segurança em testes
    // Use lógica explícita ao invés de confiar em panics
}
# Rodar testes em diferentes modos
zig build test                         # Debug (padrão)
zig build test -Doptimize=ReleaseSafe  # Release com segurança
zig build test -Doptimize=ReleaseFast  # Release sem segurança

Debug de Testes

test "debugging" {
    const valor = calcular();

    // Print para debug
    std.debug.print("\nValor calculado: {d}\n", .{valor});

    // Dump de memória
    const bytes = std.mem.asBytes(&valor);
    std.debug.print("Bytes: {x}\n", .{std.fmt.fmtSliceHexLower(bytes)});

    try expect(valor == 42);
}
# Rodar testes com output visível
zig test src/main.zig 2>&1

# Debug com GDB
zig test src/main.zig --test-cmd gdb --test-cmd-bin

Problemas com Testes no build.zig

// build.zig — configuração correta de testes
pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Testes unitários
    const tests = b.addTest(.{
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Adicionar dependências também aos testes
    const dep = b.dependency("minha_dep", .{ .target = target, .optimize = optimize });
    tests.root_module.addImport("minha_dep", dep.module("minha_dep"));

    const run_tests = b.addRunArtifact(tests);
    const test_step = b.step("test", "Rodar testes unitários");
    test_step.dependOn(&run_tests.step);
}

Veja Também

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.