---
title: "Testes com Allocator em Zig"
url: "https://ziglang.com.br/receitas/testes-com-allocator-em-zig/"
markdown_url: "https://ziglang.com.br/receitas/testes-com-allocator-em-zig.MD"
description: "Receita prática para testar código Zig que aloca memória. Uso de testing.allocator para detecção automática de leaks, padrões de teste com arena e FixedBufferAllocator."
date: "2026-02-21"
author: "Zig Brasil"
---

# Testes com Allocator em Zig

Receita prática para testar código Zig que aloca memória. Uso de testing.allocator para detecção automática de leaks, padrões de teste com arena e FixedBufferAllocator.


## Introdução

Uma das maiores vantagens de testar em Zig é o `std.testing.allocator` — um allocator especial que detecta vazamentos de memória automaticamente. Se seu código esquece de liberar memória, o teste falha com uma mensagem clara. Esta receita mostra como aproveitar isso ao máximo.

Para testes básicos, veja [Testes Unitários Básicos](/receitas/zig-teste-unitario-basico/). Para detecção de leaks em produção, consulte [Detectar Vazamentos de Memória](/receitas/zig-detectar-memory-leak/).

## Pré-requisitos

- Zig instalado (versão 0.13+). Veja o [guia de instalação](/tutoriais/como-instalar-zig/)
- Conhecimento básico de testes em Zig

## O testing.allocator

O `std.testing.allocator` é um allocator que rastreia todas as alocações e verifica, ao final do teste, que todas foram liberadas:

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

fn criarMensagem(allocator: std.mem.Allocator, nome: []const u8) ![]u8 {
    return std.fmt.allocPrint(allocator, "Olá, {s}!", .{nome});
}

test "criarMensagem libera corretamente" {
    const msg = try criarMensagem(std.testing.allocator, "Zig");
    defer std.testing.allocator.free(msg);

    try std.testing.expectEqualStrings("Olá, Zig!", msg);
}

test "ESTE TESTE FALHA - leak detectado" {
    const msg = try criarMensagem(std.testing.allocator, "Zig");
    // BUG: esqueceu de fazer free!
    // O teste FALHA automaticamente com:
    // "memory leak detected"
    _ = msg;
}
```

## Testar Structs com Allocator

```zig
const Lista = struct {
    items: std.ArrayList(i32),

    pub fn init(allocator: std.mem.Allocator) Lista {
        return .{ .items = std.ArrayList(i32).init(allocator) };
    }

    pub fn deinit(self: *Lista) void {
        self.items.deinit();
    }

    pub fn adicionar(self: *Lista, valor: i32) !void {
        try self.items.append(valor);
    }

    pub fn soma(self: Lista) i64 {
        var total: i64 = 0;
        for (self.items.items) |item| {
            total += item;
        }
        return total;
    }
};

test "Lista - operações básicas" {
    var lista = Lista.init(std.testing.allocator);
    defer lista.deinit(); // ESSENCIAL: evita leak

    try lista.adicionar(10);
    try lista.adicionar(20);
    try lista.adicionar(30);

    try std.testing.expectEqual(@as(i64, 60), lista.soma());
}

test "Lista - vazia" {
    var lista = Lista.init(std.testing.allocator);
    defer lista.deinit();

    try std.testing.expectEqual(@as(i64, 0), lista.soma());
}
```

## Testar Funções que Transferem Ownership

```zig
fn duplicarArray(allocator: std.mem.Allocator, dados: []const u8) ![]u8 {
    return allocator.dupe(u8, dados);
}

test "duplicar array - ownership transferida" {
    const original = "dados de teste";
    const copia = try duplicarArray(std.testing.allocator, original);
    defer std.testing.allocator.free(copia); // Chamador libera

    try std.testing.expectEqualStrings(original, copia);
    try std.testing.expect(original.ptr != copia.ptr); // São cópias distintas
}
```

## Testar com Arena Allocator

Para testes que fazem muitas alocações temporárias:

```zig
test "processamento complexo com arena" {
    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
    defer arena.deinit(); // Libera TUDO de uma vez

    const alloc = arena.allocator();

    // Muitas alocações sem precisar de free individual
    const a = try alloc.alloc(u8, 100);
    const b = try alloc.alloc(u8, 200);
    const c = try std.fmt.allocPrint(alloc, "{s}{s}", .{ a[0..5], b[0..5] });

    try std.testing.expect(c.len == 10);
    // arena.deinit() no defer cuida de tudo
}
```

Veja [ArenaAllocator](/receitas/zig-arena-allocator/) para mais detalhes.

## Testar que Errdefer Funciona

```zig
fn criarRecurso(allocator: std.mem.Allocator, falhar: bool) !*Recurso {
    const r = try allocator.create(Recurso);
    errdefer allocator.destroy(r);

    r.* = .{ .dados = try allocator.alloc(u8, 100) };
    errdefer allocator.free(r.dados);

    if (falhar) return error.Falha;

    return r;
}

test "errdefer libera tudo em caso de erro" {
    // Este teste verifica que NÃO há leak quando a função falha
    const resultado = criarRecurso(std.testing.allocator, true);
    try std.testing.expectError(error.Falha, resultado);
    // Se errdefer não funcionasse, testing.allocator detectaria leak
}

test "sucesso não aciona errdefer" {
    const r = try criarRecurso(std.testing.allocator, false);
    defer {
        std.testing.allocator.free(r.dados);
        std.testing.allocator.destroy(r);
    }
    try std.testing.expect(r.dados.len == 100);
}
```

Veja [Padrões Errdefer](/receitas/zig-errdefer-pattern/).

## Testar com FixedBufferAllocator

Para testes que precisam ser determinísticos ou sem heap:

```zig
test "operação cabe em buffer fixo" {
    var buffer: [1024]u8 = undefined;
    var fba = std.heap.FixedBufferAllocator.init(&buffer);
    const alloc = fba.allocator();

    const dados = try alloc.alloc(u8, 100);
    try std.testing.expectEqual(@as(usize, 100), dados.len);

    // Testar que a operação não excede o buffer
    alloc.free(dados);
}

test "detectar uso excessivo de memória" {
    var buffer: [64]u8 = undefined;
    var fba = std.heap.FixedBufferAllocator.init(&buffer);
    const alloc = fba.allocator();

    // Deve falhar se tentar alocar mais que 64 bytes
    const resultado = alloc.alloc(u8, 128);
    try std.testing.expectError(error.OutOfMemory, resultado);
}
```

Veja [FixedBufferAllocator](/receitas/zig-fixed-buffer-allocator/).

## Padrão: Helper de Teste

```zig
fn TestContext(comptime T: type) type {
    return struct {
        allocator: std.mem.Allocator,
        instancia: T,

        const Self = @This();

        pub fn init() !Self {
            const allocator = std.testing.allocator;
            return .{
                .allocator = allocator,
                .instancia = try T.init(allocator),
            };
        }

        pub fn deinit(self: *Self) void {
            self.instancia.deinit();
        }
    };
}

test "usando test context" {
    var ctx = try TestContext(MinhaStruct).init();
    defer ctx.deinit();

    try ctx.instancia.operacao();
}
```

## Boas Práticas

1. **Sempre use `std.testing.allocator`** em testes que alocam memória
2. **Sempre use `defer deinit()`** para structs com resources
3. **Teste tanto sucesso quanto falha** para verificar que errdefer funciona
4. **Use arena em testes complexos** para simplificar cleanup
5. **Verifique leaks propositalmente** para garantir que detecção funciona

## Conclusão

O `testing.allocator` é uma ferramenta essencial para qualidade de código Zig. Ele transforma leaks de memória de bugs silenciosos em falhas de teste explícitas. Use-o em todos os testes que envolvem alocação de memória.

Para mais, veja [Testes Unitários Básicos](/receitas/zig-teste-unitario-basico/), [Test Expectations](/receitas/zig-teste-expect-matchers/) e [Mocking e Stubbing](/receitas/zig-teste-mock-stub/).
