---
title: "Testando o Tempo: Simplificando Testes Assíncronos em Go"
url: "https://golang.com.br/blog/go-testando-tempo-testes-assincronos/"
markdown_url: "https://golang.com.br/blog/go-testando-tempo-testes-assincronos.MD"
description: "O pacote testing/synctest do Go 1.25 simplifica testes de codigo assincrono e concorrente. Aprenda a testar goroutines, channels e timers facilmente."
date: "2025-08-26"
author: "Go Blog (Resumo)"
---

# Testando o Tempo: Simplificando Testes Assíncronos em Go

O pacote testing/synctest do Go 1.25 simplifica testes de codigo assincrono e concorrente. Aprenda a testar goroutines, channels e timers facilmente.


O artigo do blog oficial do Go discute a importância e os desafios de testar código assíncrono, introduzindo o pacote `testing/synctest`, que agora está disponível para uso geral desde o Go 1.25, após um período como pacote experimental no Go 1.24. O pacote visa simplificar significativamente a escrita de testes para código concorrente e assíncrono.

## O que é uma Função Assíncrona?

O artigo começa definindo a diferença entre funções síncronas e assíncronas. Uma função síncrona executa uma ação e retorna um resultado imediatamente, enquanto uma função assíncrona retorna imediatamente após ser chamada, executando a ação em segundo plano, em algum momento no futuro. Um exemplo simples é a função `Cleanup` que remove um diretório de cache de forma síncrona, em contraste com `CleanupInBackground`, que executa a remoção em uma goroutine separada.

```go
func (c *Cache) Cleanup() {
    os.RemoveAll(c.cacheDir)
}

func (c *Cache) CleanupInBackground() {
    go os.RemoveAll(c.cacheDir)
}
```

Funções como `context.WithDeadline` também são assíncronas, pois criam um contexto que será cancelado em um momento futuro específico.

## Desafios dos Testes Assíncronos

Testar funções síncronas é direto: configura-se o estado inicial, chama-se a função e verifica-se o resultado. No entanto, testar funções assíncronas é mais complexo porque é preciso esperar que a operação em segundo plano seja concluída antes de verificar o resultado. Se a espera for muito curta, o teste pode falhar porque a operação ainda não foi concluída. Se a espera for muito longa, o teste se torna lento.

Um desafio ainda maior é verificar se algo *não* aconteceu. Pode-se verificar que algo não aconteceu *ainda*, mas como ter certeza de que não acontecerá *depois*?

## Exemplo Prático: Testando `context.WithDeadline`

O artigo usa a função `context.WithDeadline` como exemplo para ilustrar os desafios. Um teste comum para essa função é verificar se o contexto é cancelado após o prazo (deadline) especificado. Uma primeira tentativa de implementar esse teste pode ser:

```go
func TestWithDeadlineAfterDeadline(t *testing.T) {
    deadline := time.Now().Add(1 * time.Second)
    ctx, _ := context.WithDeadline(t.Context(), deadline)

    time.Sleep(time.Until(deadline))

    if err := ctx.Err(); err != context.DeadlineExceeded {
        t.Fatalf("context not canceled after deadline")
    }
}
```

Este teste dorme até o deadline e então verifica se o contexto foi cancelado. O problema é que o teste pode ser *flaky*, ou seja, pode falhar ocasionalmente, mesmo quando o código está correto, devido a pequenas variações no tempo de execução. Para tentar corrigir isso, pode-se adicionar um tempo extra de espera:

```go
time.Sleep(time.Until(deadline) + 100*time.Millisecond)
```

No entanto, isso torna o teste mais lento e ainda não garante que ele seja completamente confiável, especialmente em ambientes de CI (Continuous Integration) com alta carga.

## O Dilema: Lento ou Flaky

Testes que dependem do tempo real são inerentemente lentos ou flaky. Aumentar o tempo de espera torna o teste mais lento, mas reduz a probabilidade de flakiness. Diminuir o tempo de espera torna o teste mais rápido, mas aumenta a probabilidade de flakiness.

## Alternativas: Funções Síncronas e Instrumentação para Testabilidade

Uma abordagem é evitar funções assíncronas sempre que possível, favorecendo funções síncronas que podem ser executadas em goroutines separadas se necessário. Isso simplifica o teste, pois a execução da função pode ser controlada diretamente no teste.

```go
// CleanupInBackground é difícil de testar.
cache.CleanupInBackground()

// Cleanup é fácil de testar,
// e fácil de rodar em background quando necessário.
go cache.Cleanup()
```

No entanto, nem sempre é possível evitar funções assíncronas. Nesses casos, uma abordagem melhor é instrumentar o código para torná-lo mais testável. Isso envolve o uso de "fake time" (tempo falso) e a capacidade de esperar que toda a atividade em segundo plano seja concluída antes de verificar o resultado.

Um exemplo de como isso pode ser implementado para o teste `context.WithDeadline` é:

```go
func TestWithDeadlineAfterDeadline(t *testing.T) {
    clock := fakeClock()
    timeout := 1 * time.Second
    deadline := clock.Now().Add(timeout)

    ctx, _ := context.WithDeadlineClock(
        t.Context(), deadline, clock)

    clock.Advance(timeout)
    context.WaitUntilIdle(ctx)
    if err := ctx.Err(); err != context.DeadlineExceeded {
        t.Fatalf("context not canceled after deadline")
    }
}
```

Neste exemplo, `fakeClock` é uma implementação de um relógio falso que permite controlar o tempo no teste. `context.WithDeadlineClock` é uma versão modificada da função `context.WithDeadline` que aceita um relógio como parâmetro. `clock.Advance` avança o tempo no relógio falso, e `context.WaitUntilIdle` espera que todas as goroutines relacionadas ao contexto sejam concluídas.

Essa abordagem resolve os problemas de lentidão e flakiness, pois o tempo pode ser controlado de forma precisa e a conclusão das operações em segundo plano pode ser garantida antes de verificar o resultado.

Os dois princípios fundamentais de escrever código concorrente testável são:

1.  Usar tempo falso (se o código usa tempo).
2.  Ter alguma forma de esperar pela quiescência (quando toda a atividade em segundo plano é concluída).

O artigo reconhece que a instrumentação do código para testabilidade pode ser complexa, especialmente a parte de identificar quando toda a atividade em segundo plano foi concluída.

---

## Artigo Original

Este e um resumo em português do artigo original publicado no blog oficial do Go.

**Titulo original:** Testing Time (and other asynchronicities)

[Leia o artigo completo em ingles no Go Blog](https://go.dev/blog/testing-time)

*Autor original: Damien Neil*
