Descomplicando Testes Unitários em Go: Um Guia Descontraído com Exemplo Real
Vem ver como os testes unitários podem salvar seu código e sua sanidade, com exemplos práticos usando o projeto Dev Starter.
Mais um! Vamos falar sobre testes unitários em Go? Eu sei que muita gente acha que testar código é coisa de programador chato, mas vou te mostrar que isso pode ser divertido e, mais importante, super útil! Vou usar o Dev Starter, que é meu projeto sensacional que estou desenvolvendo. Ele automatiza as configurações no WSL, como exemplo.
O Que São Testes Unitários?
Testes unitários são tipo aqueles lembretes de “não se esqueça do guarda-chuva!” antes de sair de casa. Eles te avisam quando algo pode dar errado no seu código, antes que você mande ele rodar no mundo real.
Resumindo: um teste unitário garante que cada pedacinho do seu programa (uma função, método, etc.) funcione direitinho, sem causar problemas no resto.
Como Funciona o Teste Unitário em Go?
No Go, é tudo simples e direto. Para criar um teste:
- Nomeie o arquivo de teste com
_test.go
no final. - Crie uma função
func TestXxx(t *testing.T)
no pacote principal ou em um pacote separado de teste. - Dentro dessa função, use métodos do
testing.T
para validar os resultados.
O Projeto de Exemplo: Dev Starter
O Que É o Dev Starter?
O Dev Starter é meu projeto para ajudar desenvolvedores a configurar ambientes automaticamente no WSL. Ele instala editores, frameworks, e até o Nix para gerenciar pacotes. Muito prático, né?
Agora vamos colocar a mão na massa e escrever alguns testes para ele.
Claro! Vamos explicar o código parte por parte, detalhando o que cada parte faz. Aqui está o código de exemplo para o teste da função SetupWSL
, com a explicação em cada etapa.
1. Definição do Mock: MockCommandExecutor
1
2
3
4
type MockCommandExecutor struct {
Calls []string // Armazena os comandos executados
Err error // Simula um erro, se necessário
}
MockCommandExecutor
é uma struct que simula a execução de comandos.Calls
é um slice que vai armazenar todos os comandos que foram “executados”.Err
é uma variável para simular um erro, caso você precise testar como o código reage a falhas de execução de comandos.
2. Implementação do Método Execute
para o Mock
1
2
3
4
5
6
func (m *MockCommandExecutor) Execute(name string, arg ...string) error {
// Registra o comando chamado
command := name + " " + concatArgs(arg)
m.Calls = append(m.Calls, command)
return m.Err
}
- O método
Execute
simula a execução de um comando. - Ele recebe o nome do comando e seus argumentos (
name
earg
). - A função
concatArgs
é chamada para unir os argumentos em uma string única, e o comando resultante é adicionado à listaCalls
. - O método retorna um erro (se for definido) para testar situações onde a execução falha.
3. Função de Auxílio concatArgs
1
2
3
4
5
6
7
func concatArgs(args []string) string {
result := ""
for _, arg := range args {
result += arg + " "
}
return result[:len(result)-1] // Remove o último espaço extra
}
concatArgs
é uma função auxiliar para transformar um slice de strings (args
) em uma única string, onde os argumentos são separados por espaços.- No final, o último espaço é removido para garantir que a string final seja formatada corretamente.
4. Função de Teste: TestSetupWSL
1
2
func TestSetupWSL(t *testing.T) {
mockExecutor := &MockCommandExecutor{}
- Aqui, criamos uma instância de
MockCommandExecutor
chamadamockExecutor
, que usaremos para capturar os comandos que seriam executados.
5. Chamada da Função SetupWSL
com o Mock
1
2
// Executa a função com o mock
SetupWSL(mockExecutor)
- A função
SetupWSL
é chamada, passando omockExecutor
como parâmetro. Ao invés de executar comandos reais no sistema, a função agora usará o mock, o que garante que os comandos não sejam realmente executados.
6. Verificação dos Comandos Esperados
1
2
3
4
5
6
7
8
// Verifica se os comandos esperados foram chamados
expectedCommands := []string{
"powershell.exe -Command Start-Process PowerShell -Verb RunAs -ArgumentList 'Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux -All'",
"powershell.exe -Command Start-Process PowerShell -Verb RunAs -ArgumentList 'wsl --install -d Debian'",
"wsl -d Debian",
"wsl --shutdown",
"wsl -d Debian",
}
- Aqui, criamos uma lista
expectedCommands
com os comandos que esperamos que a funçãoSetupWSL
tenha chamado. - Esses são os comandos que o
mockExecutor
deverá capturar, caso a função tenha se comportado corretamente.
7. Comparação dos Comandos Executados com os Esperados
1
2
3
4
5
6
7
8
9
for i, expected := range expectedCommands {
if i >= len(mockExecutor.Calls) {
t.Fatalf("Esperava mais comandos: %s", expected)
}
if mockExecutor.Calls[i] != expected {
t.Errorf("Comando #%d incorreto: esperado '%s', obteve '%s'", i+1, expected, mockExecutor.Calls[i])
}
}
- Loop: Para cada comando na lista
expectedCommands
, comparamos se o comando registrado no mock é o mesmo. - Se o número de comandos executados for menor do que o esperado, o teste falha com uma mensagem dizendo que faltou um comando.
- Se algum comando não corresponder, o teste falha e indica qual comando foi esperado e qual foi executado de fato.
8. Verificação do Número de Comandos Executados
1
2
3
if len(mockExecutor.Calls) != len(expectedCommands) {
t.Errorf("Número de comandos incorreto: esperado %d, obteve %d", len(expectedCommands), len(mockExecutor.Calls))
}
- Aqui, verificamos se o número total de comandos executados corresponde ao número de comandos esperados.
- Se o número de comandos for diferente, o teste falha. Claro! Vamos separar a parte 3 do processo, que é “Rodando os Testes”, em detalhes para você entender melhor o que fazer:
8. Rodando os Testes
Agora que você escreveu os testes, o próximo passo é rodá-los para verificar se tudo está funcionando corretamente. Para rodar seus testes em Go, você vai usar o comando go test
.
Passos para Rodar os Testes:
Abrir o Terminal: Navegue até o diretório onde seu código de testes está localizado.
Rodar o Comando para Testar:
Execute o seguinte comando no terminal:
1 2
# use a pasta em que o arquivo de teste está: no meu caso ta em config go test -v ./config
O
-v
é uma opção que significa “verbose”, ou seja, vai mostrar um output mais detalhado dos testes que estão sendo executados.
O Que Acontece Quando Você Roda os Testes?
Se os testes passarem, você verá algo assim no terminal:
1 2 3 4
=== RUN TestSetupWSL --- PASS: TestSetupWSL (0.00s) PASS ok seu_pacote/config 0.001s
Isso indica que o teste foi bem-sucedido.
No meu ficou assim:
1
2
3
4
5
6
7
8
9
10
11
$ go test -v ./config
=== RUN TestSetupWSL
time="2024-12-16T10:21:23-03:00" level=info msg="WSL habilitado com sucesso! Preparando o ambiente Linux no Windows..."
time="2024-12-16T10:21:23-03:00" level=info msg="Debian instalado! Linux está a caminho..."
time="2024-12-16T10:21:23-03:00" level=info msg="Debian aberto para configuração inicial. Aproveite essa experiência Linux!"
time="2024-12-16T10:21:53-03:00" level=info msg="WSL encerrado. Vamos continuar a configuração!"
--- PASS: TestSetupWSL (30.00s)
PASS
ok github.com/bl4ckw1d0w/dev-starter/config (cached)
Se os testes falharem, você verá algo assim no terminal:
1 2 3 4 5 6
=== RUN TestSetupWSL --- FAIL: TestSetupWSL (0.00s) setup_wsl_test.go:XX: Os comandos executados não coincidem com os esperados FAIL exit status 1 FAIL seu_pacote/config 0.001s
Neste caso, o teste falhou e você receberá uma mensagem de erro com detalhes sobre o que deu errado. O número XX representa a linha onde o erro ocorreu no arquivo de teste.
Rodar Testes com Cobertura:
1
2
3
4
5
Se quiser gerar um relatório de cobertura de testes, use:
```bash
go test -cover
```
Pode dar uma olhada na minha PR no repositório no GitHub para dar uma olhada no codigo de teste e o de origem.
Dicas Para Escrever Testes
- Mantenha os testes simples e focados. Cada teste deve testar um único comportamento.
- Mocks são seus melhores amigos. Não teste comandos reais que podem causar bagunça no seu ambiente.
- Use bibliotecas como
testify
para facilitar seus asserts.
Tendo dito…
Testar o código não precisa ser uma tarefa chata! Com as ferramentas certas e uma abordagem mais modular, você garante que seu código vai funcionar direitinho. E lembre-se: sempre rode seus testes antes de mandar aquele PR. 😉
Espero que tenha curtido esse guia rapidinho! Agora, que tal testar tudo no Dev Starter?