Testes unitários nos ajudam muito a tentar manter a quantidade de bugs baixa, já que podemos testar várias hipóteses de forma automática. E por ser automatizada, a cada mudança que fazemos, os testes unitários também nos ajudam a garantir que não quebramos o sistema em partes que nem tocamos mas que dependem das mudanças que fizemos.
Embora exista alguns packages que ajudam na escrita dos testes unitários, a recomendação do time de desenvolvimento da linguagem é que os testes sejam escritos usando o package nativo da linguagem, pelo simples fato de que um package externo pode adicionar algum bug ou realizar algum teste de forma incorreta.
Antes de começar a escrever os testes, vamos criar um arquivo chamado soma.go e escrever uma pequena função que soma N valores.
package soma
func Soma(valores ...int) (total int) {
for _, valor := range valores {
total += valor
}
return
}
Feito isso, agora precisamos criar o arquivo para testar essa função. Por convenção, os arquivos de teste são criados no mesmo local onde o arquivo que ele está testando, e nome do arquivo tem o sufixo _test adicionado ao nome do arquivo onde estão as funções que ele testa.
No nosso caso, vamos criar o soma_test.go e criar a função TestSoma.
package soma
import "testing"
func TestSoma(t *testing.T) {
test := []int{1, 2, 3, 4}
total := Soma(test...)
if total != 10 {
t.Fatalf("Valor esperado: 10 - Valor retornado: %d", total)
}
}
Feito isso, tudo que precisamos fazer agora é executar o comando abaixo:
$ go test ./...
O output deverá ser algo similar a isso:
ok github.com/aprendagolang/soma 0.011s
Simples não?! Porém nós só estamos testando uma hipótese, o que praticamente não testa nossa função de verdade.
Para melhorar isso, vamos fazer uma pequena mudança na nossa função de teste para que possamos testar várias hipóteses, aumentando a garantia de que a função não contém bugs.
package soma
import "testing"
func TestSoma(t *testing.T) {
testes := []struct {
Valores []int
Resultado int
}{
{Valores: []int{1, 2, 3}, Resultado: 6},
{Valores: []int{1, 2, 3, 4}, Resultado: 10},
{Valores: []int{3, 3, 3, 3}, Resultado: 12},
{Valores: []int{1, 1, 1, 1}, Resultado: 4},
{Valores: []int{12, 20, 35}, Resultado: 67},
{Valores: []int{19, 21, 32}, Resultado: 72},
}
for _, teste := range testes {
total := Soma(teste.Valores...)
if total != teste.Resultado {
t.Fatalf("Valor esperado: %d - Valor retornado: %d", teste.Resultado, total)
}
}
}
Ao invés de ficar duplicando, triplicando, quadru… você entendeu… as linhas que tínhamos escrito inicialmente, criamos uma struct dentro da função, onde passamos os Valores a serem testados e o Resultado esperado. Dessa forma fica muito mais simples adicionar novas hipóteses que queremos testar, como por exemplo, o que acontece se um dos valores passados for nill??? Vamos adicionar essa hipótese abaixo.
package soma
import "testing"
func TestSoma(t *testing.T) {
comNill := make([]int, 3)
comNill[0] = 10
comNill[1] = 10
testes := []struct {
Valores []int
Resultado int
}{
{Valores: []int{1, 2, 3}, Resultado: 6},
{Valores: []int{1, 2, 3, 4}, Resultado: 10},
{Valores: []int{3, 3, 3, 3}, Resultado: 12},
{Valores: []int{1, 1, 1, 1}, Resultado: 4},
{Valores: []int{12, 20, 35}, Resultado: 67},
{Valores: []int{19, 21, 32}, Resultado: 72},
{Valores: comNill, Resultado: 20},
}
for _, teste := range testes {
total := Soma(teste.Valores...)
if total != teste.Resultado {
t.Fatalf("Valor esperado: %d - Valor retornado: %d", teste.Resultado, total)
}
}
}
Executando o go test ./... podemos ver que tudo continua funcionando normal.
Uma última mudança que podemos fazer, é adicionar o sufixo _test ao nome do package dentro do arquivo soma_test.go. Dessa forma, vamos testar a função como se ela estivesse sendo utilizada fora do package no qual ela foi criada.
Após essa mudança, precisamos fazer o import do package e mudar a chamada da função.
package soma_test
import (
"testing"
"github.com/aprendagolang/soma"
)
func TestSoma(t *testing.T) {
comNill := make([]int, 3)
comNill[0] = 10
comNill[1] = 10
testes := []struct {
Valores []int
Resultado int
}{
{Valores: []int{1, 2, 3}, Resultado: 6},
{Valores: []int{1, 2, 3, 4}, Resultado: 10},
{Valores: []int{3, 3, 3, 3}, Resultado: 12},
{Valores: []int{1, 1, 1, 1}, Resultado: 4},
{Valores: []int{12, 20, 35}, Resultado: 67},
{Valores: []int{19, 21, 32}, Resultado: 72},
{Valores: comNill, Resultado: 20},
}
for _, teste := range testes {
total := soma.Soma(teste.Valores...)
if total != teste.Resultado {
t.Fatalf("Valor esperado: %d - Valor retornado: %d", teste.Resultado, total)
}
}
}
Espero que tenham gostado, e se ficou alguma dúvida, deixe nos comentários.
Até a próxima!
Faça parte da comunidade!
Receba os melhores conteúdos sobre Go, Kubernetes, arquitetura de software, Cloud e esteja sempre atualizado com as tendências e práticas do mercado.
Livros Recomendados
Abaixo listei alguns dos melhores livros que já li sobre GO.

