Zig possui um dos sistemas de testes mais elegantes entre linguagens de programacao de sistemas. Testes sao cidadaos de primeira classe na linguagem — nao ha necessidade de frameworks, bibliotecas externas ou configuracoes complexas. Neste artigo, exploramos os fundamentos do sistema de testes built-in do Zig e como usa-lo efetivamente.
Para o basico de testes em Zig, confira Testes em Zig.
O Sistema de Testes do Zig
Testes em Zig sao blocos test declarados junto ao codigo. Eles sao executados com zig build test ou zig test arquivo.zig.
Primeiro Teste
const std = @import("std");
const expect = std.testing.expect;
fn soma(a: i32, b: i32) i32 {
return a + b;
}
test "soma basica" {
try expect(soma(2, 3) == 5);
try expect(soma(-1, 1) == 0);
try expect(soma(0, 0) == 0);
}
test "soma com overflow" {
// Zig detecta overflow em modo debug
try expect(soma(std.math.maxInt(i32), 0) == std.math.maxInt(i32));
}
Execute com:
zig test arquivo.zig
# Saida: All 2 tests passed.
Tipos de Assertions
const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const expectError = std.testing.expectError;
const expectEqualStrings = std.testing.expectEqualStrings;
const expectEqualSlices = std.testing.expectEqualSlices;
const expectApproxEqAbs = std.testing.expectApproxEqAbs;
test "tipos de assertions" {
// Igualdade basica
try expectEqual(@as(i32, 42), soma(40, 2));
// Strings
const nome = "Zig Brasil";
try expectEqualStrings("Zig Brasil", nome);
// Slices
const a = [_]u8{ 1, 2, 3 };
const b = [_]u8{ 1, 2, 3 };
try expectEqualSlices(u8, &a, &b);
// Floats (com tolerancia)
try expectApproxEqAbs(@as(f64, 3.14159), @as(f64, 3.14160), 0.001);
}
Testando Erros
Um dos pontos fortes do Zig e o tratamento explicito de erros, e o sistema de testes reflete isso:
const std = @import("std");
const expect = std.testing.expect;
const expectError = std.testing.expectError;
const MathError = error{
DivisaoPorZero,
Overflow,
};
fn dividir(a: i32, b: i32) MathError!i32 {
if (b == 0) return MathError.DivisaoPorZero;
return @divTrunc(a, b);
}
test "divisao normal" {
const resultado = try dividir(10, 2);
try expect(resultado == 5);
}
test "divisao por zero retorna erro" {
try expectError(MathError.DivisaoPorZero, dividir(10, 0));
}
test "divisao com catch" {
const resultado = dividir(10, 0) catch |err| {
try expect(err == MathError.DivisaoPorZero);
return;
};
_ = resultado;
// Se chegou aqui, o teste deveria ter falhado
return error.TestExpectedError;
}
Testes Parametrizados com Comptime
O comptime de Zig permite criar testes parametrizados sem macros:
const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
fn fatorial(n: u64) u64 {
if (n <= 1) return 1;
return n * fatorial(n - 1);
}
test "fatorial parametrizado" {
const casos = .{
.{ 0, 1 },
.{ 1, 1 },
.{ 2, 2 },
.{ 3, 6 },
.{ 4, 24 },
.{ 5, 120 },
.{ 10, 3628800 },
};
inline for (casos) |caso| {
const entrada = caso[0];
const esperado = caso[1];
try expectEqual(@as(u64, esperado), fatorial(entrada));
}
}
Gerando Testes para Multiplos Tipos
const std = @import("std");
const expect = std.testing.expect;
fn maxGenerico(comptime T: type, a: T, b: T) T {
return if (a > b) a else b;
}
fn testarMax(comptime T: type) !void {
try expect(maxGenerico(T, 1, 2) == 2);
try expect(maxGenerico(T, 5, 3) == 5);
try expect(maxGenerico(T, 7, 7) == 7);
}
test "max para i32" {
try testarMax(i32);
}
test "max para u64" {
try testarMax(u64);
}
test "max para f32" {
try testarMax(f32);
}
Allocator de Teste
O std.testing.allocator detecta memory leaks automaticamente:
const std = @import("std");
const expect = std.testing.expect;
fn duplicarString(allocator: std.mem.Allocator, str: []const u8) ![]u8 {
const copia = try allocator.alloc(u8, str.len);
@memcpy(copia, str);
return copia;
}
test "duplicar string sem leak" {
const resultado = try duplicarString(std.testing.allocator, "teste");
defer std.testing.allocator.free(resultado);
try std.testing.expectEqualStrings("teste", resultado);
}
// Se voce esquecer o defer free, o teste FALHA com:
// "Test leaked memory" - detectado automaticamente!
Organizando Testes em Projetos
Testes no Mesmo Arquivo
// src/calculadora.zig
pub fn soma(a: i32, b: i32) i32 {
return a + b;
}
pub fn multiplica(a: i32, b: i32) i32 {
return a * b;
}
// Testes ficam no mesmo arquivo — removidos do binario de producao
test "operacoes basicas" {
const expect = @import("std").testing.expect;
try expect(soma(2, 3) == 5);
try expect(multiplica(3, 4) == 12);
}
Referenciando Testes de Submodulos
// src/main.zig ou src/root.zig
const calculadora = @import("calculadora.zig");
const parser = @import("parser.zig");
const utils = @import("utils.zig");
// Forcar execucao de testes em todos os modulos
comptime {
_ = calculadora;
_ = parser;
_ = utils;
}
// Testes especificos de integracao
test "integracao calculadora-parser" {
// ...
}
Configurando no build.zig
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Executavel principal
const exe = b.addExecutable(.{
.name = "meu-projeto",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
// Testes
const testes = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const run_testes = b.addRunArtifact(testes);
const test_step = b.step("test", "Executar testes");
test_step.dependOn(&run_testes.step);
b.installArtifact(exe);
}
Exercicios
Stack com testes: Implemente uma stack generica com testes para push, pop, peek, isEmpty e deteccao de leak.
Parser de CSV: Crie um parser de CSV simples com testes parametrizados cobrindo edge cases (campos vazios, aspas, newlines).
Testes de contrato: Escreva testes que verifiquem invariantes de uma estrutura de dados (ex: BST sempre ordenada).
Proximo Artigo
No proximo artigo, exploramos padroes de teste avancados: mocks, stubs, dependency injection e table-driven tests.
Conteudo Relacionado
- Testes em Zig — Introducao
- Zig Build System — Configuracao de testes
- Tratamento de Erros em Zig — Error unions
Duvidas sobre testes em Zig? Participe da comunidade Zig Brasil!