DEV Community

Danilo Machado
Danilo Machado

Posted on

4

Introdução aos testes unitários em Go

Os testes unitários são testes que verificam se uma parte específica do código, costumeiramente a nível de função, está funcionando corretamente. Em um ambiente orientado a objetos é usualmente a nível de classes e a mínima unidade de testes inclui construtores e destrutores.

Por qual motivo devo realizar testes unitários na minha aplicação?
Mas o verdadeiro propósito do teste unitário é fornecer-lhe feedback quase instantâneo sobre o projeto e a implementação de seu código. A criação de testes unitários, ou melhor, a facilidade ou dificuldade com que você pode criá-los lhe diz exatamente o quão testável é seu código. O quão bem você o projetou.

No nosso exemplo, vamos simular um teste unitário em uma função que faz a validação de um symbol de criptomoedas bem simples mas que foi retirado de produção.

package main
import (
"fmt"
"log"
"strings"
)
var (
errSymbolInvalid = fmt.Errorf("Symbol should contain '/' between the assets")
)
func validationSymbol(symbol string) (err error) {
split := strings.Split(symbol, "/")
if len(split) != 2 {
return errSymbolInvalid
}
return
}
func main() {
symbol := "BTC/USDT"
if err := validationSymbol(symbol); err != nil {
log.Fatalln(err)
}
fmt.Println(symbol, "is valid.")
}

Todo o teste unitário necessita de um planejamento prévio. Deve ser de entendimento do desenvolvedor os requisitos que aquela funcionalidade tem que cobrir, qual a sua entrada e qual a sua saída e como se processa o fluxo interno dos dados. Logo, nesse primeiro momento, podemos observar a função e notar que existem dois cenários que não podem faltar, sendo ele o cenário de sucesso e o cenário de falha. Pra isso usaremos a lib mais utilizada que é a testify.

Na documentação do testify tem alguns exemplos, seguindo os cenários de teste unitário que definimos para nossa função, o código iniciaria parecido com esse.

package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidationSymbol(t *testing.T) {
assert := assert.New(t)
t.Run("Cenário 1 - Falha", func(t *testing.T) {
})
t.Run("Cenário 1 - Sucesso", func(t *testing.T) {
})
}

Para testar nosso cenário de falha, basta chamarmos nossa função passando um parâmetro inválido sem a barra e comparar se o erro vindo da função é igual ao erro que definimos para ela.

package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidationSymbol(t *testing.T) {
assert := assert.New(t)
t.Run("Cenário 1 - Falha", func(t *testing.T) {
err := validationSymbol("BTC-USDT")
assert.Equal(err.Error(), errSymbolInvalid.Error())
})
t.Run("Cenário 1 - Sucesso", func(t *testing.T) {
})
}

E no caso do sucesso, basta validarmos que a função não retorne erro, por passar o parâmetro adequadamente.

package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidationSymbol(t *testing.T) {
assert := assert.New(t)
t.Run("Cenário 1 - Falha", func(t *testing.T) {
err := validationSymbol("BTC-USDT")
assert.Equal(err.Error(), errSymbolInvalid.Error())
})
t.Run("Cenário 1 - Sucesso", func(t *testing.T) {
err := validationSymbol("BTC/USDT")
assert.Nil(err)
})
}

Digite go test -p 1 -covermode=atomic -tags=unit para rodar os testes unitários ou use os atalhos do vscode, caso utilize. Você deverá visualizar o retorno com algo parecido a isso:

=== RUN   TestValidationSymbol
=== RUN   TestValidationSymbol/Cenário_1_-_Falha
=== RUN   TestValidationSymbol/Cenário_1_-_Sucesso
--- PASS: TestValidationSymbol (0.00s)
    --- PASS: TestValidationSymbol/Cenário_1_-_Falha (0.00s)
    --- PASS: TestValidationSymbol/Cenário_1_-_Sucesso (0.00s)
PASS
ok
Enter fullscreen mode Exit fullscreen mode

Claro, essa é só uma introdução, a lib testify tem diversas validações que facilitam a implementação de testes unitários no dia-a-dia, em produção usamos em coisas mais complexas como validar métodos que retornam dados do banco de dados, métodos que fazem validações, métodos responsáveis por gerenciar endpoints e até mesmo com essa lib, conseguimos fazer os testes de integração, que seria um outro assunto.

Lembre-se, sempre que alterar um método ou função, você deve também alterar o teste unitário, pra isso, temos algumas formas de facilitar a checagem dos testes para verificar se teve alguma alteração, criando um atalho no Makefile por exemplo e chamando na pipeline do repositório ou até mesmo rodando localmente antes de subir sua branch.

Para rodar o comando do exemplo, basta digitar: make run-test

run-test:
go test -p 1 -covermode=atomic -tags=unit
view raw Makefile hosted with ❤ by GitHub

É isso. Recomendo a leitura também de artigos sobre criação de mocks, pois muitas das vezes irá precisar de mocks para realizar testes unitários, um exemplo são chamadas de outros serviços, elas precisarão ser feitas via mock.

Até a próxima!

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

Cloudinary image

Zoom pan, gen fill, restore, overlay, upscale, crop, resize...

Chain advanced transformations through a set of image and video APIs while optimizing assets by 90%.

Explore

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay