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
- FAQ Iniciantes — Como rodar testes
- Crash em Runtime — Crashes durante testes
- Memory Leak — Detectar leaks em testes
- Erros no build.zig — Configurar testes no build
- Receitas — Exemplos de código testado