Especialização em Backend com Go & Gin • Demonstrações Práticas Compiláveis


💻 Código de Exemplo 01 — Teste de Handler Gin com httptest e testify/assert

package handlers_test

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
)

func configurarRouterTeste() *gin.Engine {
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"msg": "pong"})
	})
	return r
}

// TestPingHandler despacha a requisição direto no Engine, sem abrir porta
// TCP: ServeHTTP roda a cadeia de middlewares e o handler em memória.
func TestPingHandler(t *testing.T) {
	r := configurarRouterTeste()

	w := httptest.NewRecorder()
	req := httptest.NewRequest(http.MethodGet, "/ping", nil)
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	assert.JSONEq(t, `{"msg":"pong"}`, w.Body.String())
}

💻 Código de Exemplo 02 — Mock de Repositório com testify/mock

package service_test

import (
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

type Produto struct {
	ID    uint
	Preco float64
}

type ProdutoRepository interface {
	BuscarPorID(id uint) (*Produto, error)
}

type MockProdutoRepo struct{ mock.Mock }

func (m *MockProdutoRepo) BuscarPorID(id uint) (*Produto, error) {
	args := m.Called(id)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*Produto), args.Error(1)
}

// CalcularDescontoVIP é a regra de negócio pura sob teste: 10% de desconto.
func CalcularDescontoVIP(repo ProdutoRepository, id uint) (float64, error) {
	p, err := repo.BuscarPorID(id)
	if err != nil {
		return 0, err
	}
	return p.Preco * 0.9, nil
}

func TestCalcularDescontoVIP_ProdutoExiste(t *testing.T) {
	mockRepo := new(MockProdutoRepo)
	mockRepo.On("BuscarPorID", uint(1)).Return(&Produto{ID: 1, Preco: 100.0}, nil)

	preco, err := CalcularDescontoVIP(mockRepo, 1)

	assert.NoError(t, err)
	assert.Equal(t, 90.0, preco)
	mockRepo.AssertExpectations(t)
}

func TestCalcularDescontoVIP_ProdutoInexistente(t *testing.T) {
	mockRepo := new(MockProdutoRepo)
	mockRepo.On("BuscarPorID", uint(99)).Return(nil, errors.New("não encontrado"))

	_, err := CalcularDescontoVIP(mockRepo, 99)

	assert.Error(t, err)
}

💻 Código de Exemplo 03 — Teste de Integração com SQLite em Memória e Benchmark

package integration_test

import (
	"encoding/json"
	"testing"

	"github.com/stretchr/testify/require"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

type Produto struct {
	ID    uint `gorm:"primaryKey"`
	Nome  string
	Preco float64
}

// configurarBancoTeste sobe um SQLite in-memory isolado por processo de
// teste e roda as migrações reais, validando queries e constraints de fato.
func configurarBancoTeste(t *testing.T) *gorm.DB {
	db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
	require.NoError(t, err)
	require.NoError(t, db.AutoMigrate(&Produto{}))
	return db
}

func TestCriarEBuscarProduto(t *testing.T) {
	db := configurarBancoTeste(t)

	produto := Produto{Nome: "Monitor", Preco: 899.90}
	require.NoError(t, db.Create(&produto).Error)

	var encontrado Produto
	require.NoError(t, db.First(&encontrado, produto.ID).Error)
	require.Equal(t, "Monitor", encontrado.Nome)
}

// BenchmarkJsonSerialization mede ns/op e allocs/op com `go test -bench=. -benchmem`.
func BenchmarkJsonSerialization(b *testing.B) {
	p := Produto{ID: 10, Nome: "Benchmark", Preco: 49.9}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, _ = json.Marshal(p)
	}
}