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!