80/100 Dias de Golang - Mini Servidor de CI/CD – Parte 4 - Adicionando testes ao repositório!
Table of Contents
#
Mini Servidor de CI/CD – Parte 4: Adicionando testes ao repositório!
Finalizamos a implementação da API e a execução dos pipelines. Agora é hora de garantir que tudo isso funcione como esperado com testes automatizados. Para fazer os testes vamos instalar a go get github.com/stretchr/testify
e criar nosso arquivo: internal/api/test/handlers_test.go
Vamos iniciar criando um setup para nossos testes. Para isso vamos criar um banco em memória.
func setupTestRouter() *gin.Engine {
database, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
db.DB = database
db.DB.AutoMigrate(&models.Pipeline{}, &models.Step{}, &models.Execution{})
r := gin.Default()
api.RegisterRoutes(r)
return r
}
Primeiro vamos testar a criação de um pipeline. Devemos esperar desse request um retorno de sucesso.
func TestCreatePipeline(t *testing.T) {
router := setupTestRouter()
payload := map[string]interface{}{
"name": "Pipeline Teste",
"repo": "https://github.com/exemplo/teste",
"steps": []map[string]interface{}{
{"order": 1, "command": "echo Testando"},
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "/pipelines", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
}
Agora vamos testar a listagem dos pipelines, vamos inserir um dado manualmente no banco de dados.
func TestGetAllPipelines(t *testing.T) {
router := setupTestRouter()
db.DB.Create(&models.Pipeline{
Name: "Teste",
Repo: "https://github.com/x/y",
Steps: []models.Step{
{Order: 1, Command: "echo step"},
},
})
req, _ := http.NewRequest("GET", "/pipelines", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "Teste")
}
E agora adicionar um teste de sucesso para a execução de um pipeline e um teste de falha:
func TestRunPipelineSuccess(t *testing.T) {
router := setupTestRouter()
pipeline := models.Pipeline{
Name: "Runner Test",
Repo: "https://fake.repo",
Steps: []models.Step{
{Order: 1, Command: "echo sucesso"},
},
}
db.DB.Create(&pipeline)
url := "/pipelines/run/" + strconv.Itoa(int(pipeline.ID))
req, _ := http.NewRequest("POST", url, nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "sucesso")
}
func TestRunPipelineFailure(t *testing.T) {
router := setupTestRouter()
pipeline := models.Pipeline{
Name: "Runner Falha",
Repo: "https://fake.repo",
Steps: []models.Step{
{Order: 1, Command: "exit 1"},
},
}
db.DB.Create(&pipeline)
url := "/pipelines/run/" + strconv.Itoa(int(pipeline.ID))
req, _ := http.NewRequest("POST", url, nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.Contains(t, w.Body.String(), "Erro na execução")
}
O arquivo completo fica da seguinte forma:
package test
import (
"bytes"
"cicd-server/internal/api"
"cicd-server/internal/db"
"cicd-server/internal/models"
"encoding/json"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func setupTestRouter() *gin.Engine {
// Banco em memória para testes
database, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
db.DB = database
db.DB.AutoMigrate(&models.Pipeline{}, &models.Step{}, &models.Execution{})
r := gin.Default()
api.RegisterRoutes(r)
return r
}
func TestCreatePipeline(t *testing.T) {
router := setupTestRouter()
payload := map[string]interface{}{
"name": "Pipeline Teste",
"repo": "https://github.com/exemplo/teste",
"steps": []map[string]interface{}{
{"order": 1, "command": "echo Testando"},
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "/pipelines", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
}
func TestGetAllPipelines(t *testing.T) {
router := setupTestRouter()
// Inserir dados manualmente
db.DB.Create(&models.Pipeline{
Name: "Teste",
Repo: "https://github.com/x/y",
Steps: []models.Step{
{Order: 1, Command: "echo step"},
},
})
req, _ := http.NewRequest("GET", "/pipelines", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "Teste")
}
func TestRunPipelineSuccess(t *testing.T) {
router := setupTestRouter()
pipeline := models.Pipeline{
Name: "Runner Test",
Repo: "https://fake.repo",
Steps: []models.Step{
{Order: 1, Command: "echo sucesso"},
},
}
db.DB.Create(&pipeline)
url := "/pipelines/run/" + strconv.Itoa(int(pipeline.ID))
req, _ := http.NewRequest("POST", url, nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "sucesso")
}
func TestRunPipelineFailure(t *testing.T) {
router := setupTestRouter()
pipeline := models.Pipeline{
Name: "Runner Falha",
Repo: "https://fake.repo",
Steps: []models.Step{
{Order: 1, Command: "exit 1"},
},
}
db.DB.Create(&pipeline)
url := "/pipelines/run/" + strconv.Itoa(int(pipeline.ID))
req, _ := http.NewRequest("POST", url, nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.Contains(t, w.Body.String(), "Erro na execução")
}
E para rodar os testes exeutamos:
go test ./...