Testing en Go 2026: Tests Unitarios, Mocks y Preguntas de Entrevista Técnica
Guía completa sobre testing en Go: escritura de tests unitarios con el paquete testing, creación de mocks con gomock, tests basados en tablas y preparación para entrevistas técnicas.

El framework de testing de Go se basa en el paquete estándar testing, incluido en cada instalación de Go sin dependencias externas. A diferencia de frameworks en otros lenguajes, el enfoque de Go privilegia la simplicidad: los archivos de test conviven con el código de producción, las funciones de test siguen una convención de nomenclatura, y el comando go test maneja el descubrimiento y la ejecución.
Candidatos que escriben tests basados en tablas, utilizan interfaces para inyección de dependencias y comprenden cuándo el mocking aporta valor versus cuándo añade ruido.
Escritura de Tests Unitarios con el Paquete testing
Cada archivo de test termina con _test.go y pertenece al mismo paquete que el código que prueba. Las funciones de test comienzan con Test seguido de un nombre en mayúscula. El parámetro *testing.T proporciona métodos para reportar fallos.
package calculator
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("Add(2, 3) = %d; want 5", result)
}
}La ejecución de go test ./... lanza todos los tests del módulo actual. El flag -v muestra los nombres de los tests individuales y su estado.
Tests Basados en Tablas: El Estándar de Go
Los tests basados en tablas reducen la duplicación y hacen trivial agregar nuevos casos. Cada fila de la tabla representa un escenario con sus entradas y salidas esperadas. Este patrón aparece en la biblioteca estándar de Go y en bases de código en producción.
package validator
import "testing"
func TestValidateEmail(t *testing.T) {
tests := []struct {
name string
email string
wantErr bool
}{
{"valid email", "user@example.com", false},
{"missing at sign", "userexample.com", true},
{"empty string", "", true},
{"unicode local part", "user@例え.jp", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateEmail(tt.email)
if (err != nil) != tt.wantErr {
t.Errorf("ValidateEmail(%q) error = %v, wantErr %v",
tt.email, err, tt.wantErr)
}
})
}
}El método t.Run crea subtests que se ejecutan independientemente. Los subtests fallidos indican qué caso específico falló sin detener los demás casos.
Inyección de Dependencias mediante Interfaces
Las interfaces de Go permiten probar código que depende de sistemas externos: bases de datos, clientes HTTP, sistemas de archivos. Definir una interfaz mínima en el punto de uso permite sustituir implementaciones reales por dobles de test.
package order
// Repository defines the data access methods this service needs
type Repository interface {
FindByID(id string) (*Order, error)
Save(order *Order) error
}
// Service handles order business logic
type Service struct {
repo Repository
}
// NewService creates a service with the given repository
func NewService(repo Repository) *Service {
return &Service{repo: repo}
}
// Process validates and saves an order
func (s *Service) Process(order *Order) error {
if order.Total <= 0 {
return ErrInvalidTotal
}
return s.repo.Save(order)
}El Service acepta cualquier tipo que satisfaga Repository. El código de producción pasa una implementación conectada a la base de datos. Los tests pasan un mock o stub.
Mocking con gomock y mockgen
El paquete gomock genera implementaciones mock a partir de definiciones de interface. El comando mockgen lee archivos fuente y produce structs mock que registran llamadas y retornan valores configurados.
# Generate mocks for the Repository interface
mockgen -source=service.go -destination=mocks/repository_mock.go -package=mocksUso del mock generado en tests:
package order
import (
"testing"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"yourmodule/order/mocks"
)
func TestService_Process_SavesValidOrder(t *testing.T) {
ctrl := gomock.NewController(t)
mockRepo := mocks.NewMockRepository(ctrl)
order := &Order{ID: "123", Total: 99.99}
// Expect Save to be called once with this order, return nil
mockRepo.EXPECT().
Save(order).
Return(nil).
Times(1)
svc := NewService(mockRepo)
err := svc.Process(order)
assert.NoError(t, err)
}
func TestService_Process_RejectsZeroTotal(t *testing.T) {
ctrl := gomock.NewController(t)
mockRepo := mocks.NewMockRepository(ctrl)
// No calls expected to repo since validation fails first
svc := NewService(mockRepo)
err := svc.Process(&Order{ID: "456", Total: 0})
assert.ErrorIs(t, err, ErrInvalidTotal)
}El mock verifica que Save fue llamado exactamente una vez con el argumento esperado. Si el código bajo prueba nunca llama a Save, o lo llama con argumentos diferentes, el test falla.
Uso de testify para Assertions y Suites
testify proporciona funciones de assertion que producen mensajes de fallo más claros que las verificaciones manuales con if. El paquete assert continúa la ejecución después de los fallos. El paquete require detiene el test inmediatamente.
package user
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestParseUser(t *testing.T) {
input := `{"id": "u1", "name": "Alice"}`
user, err := ParseUser(input)
require.NoError(t, err, "parsing should not fail")
assert.Equal(t, "u1", user.ID)
assert.Equal(t, "Alice", user.Name)
assert.Empty(t, user.Email, "email should default to empty")
}La llamada require.NoError detiene el test si el parsing falla, evitando panics de puntero nil en las assertions siguientes.
¿Listo para aprobar tus entrevistas de Go?
Practica con nuestros simuladores interactivos, flashcards y tests técnicos.
Testing de Handlers HTTP con httptest
El paquete net/http/httptest proporciona ResponseRecorder para capturar la salida de handlers y Server para ejecutar un servidor de test local. La mayoría de los tests unitarios usan ResponseRecorder para evitar la sobrecarga de red.
package api
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestHealthHandler(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/health", nil)
rec := httptest.NewRecorder()
HealthHandler(rec, req)
assert.Equal(t, http.StatusOK, rec.Code)
assert.JSONEq(t, `{"status": "ok"}`, rec.Body.String())
}Para handlers que llaman servicios externos, conviene inyectar un cliente mock o usar httptest.NewServer para crear un backend ficticio.
Preguntas de Entrevista Comunes sobre Testing en Go
Los entrevistadores evalúan el conocimiento de testing a través de preguntas que revelan experiencia con bases de código reales. Estos son los patrones que distinguen a los candidatos preparados:
«¿Cómo probarías una función que llama a una API externa?»
Se debe definir una interfaz para el cliente HTTP, inyectarla en la función o struct, y proporcionar un mock que retorne respuestas predeterminadas. Esto evita llamadas de red y hace los tests determinísticos.
«¿Cuándo usarías un stub versus un mock?»
Los stubs retornan respuestas predefinidas sin verificar cómo fueron llamados. Los mocks verifican que métodos específicos fueron llamados con argumentos específicos. Los stubs son preferibles cuando el valor de retorno importa más que la interacción. Los mocks convienen cuando verificar la interacción es el objetivo del test.
«¿Qué son los tests basados en tablas y por qué Go los privilegia?»
Los tests basados en tablas definen casos de test como datos en un slice de structs. Reducen el código repetitivo, hacen trivial agregar casos y producen salida de test legible con t.Run. Este patrón se alinea con la preferencia de Go por código explícito y repetitivo sobre abstracciones complejas.
«¿Cómo manejas fixtures de test o setup compartido por múltiples tests?»
Se recomienda usar TestMain para setup y teardown a nivel de paquete, y funciones helper o suites de tests (via testify) para setup compartido entre tests relacionados. El estado global que crea acoplamiento entre tests debe evitarse.
Para preparar una entrevista de Go, el módulo de testing Go cubre estos patrones en profundidad con preguntas prácticas.
Ejecución de Tests con Cobertura y Detección de Race Conditions
El comando go test acepta flags que revelan paths de código no probados y bugs de concurrencia.
# Run tests with coverage report
go test -cover ./...
# Generate HTML coverage visualization
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# Detect race conditions (slower, but catches real bugs)
go test -race ./...El detector de race instrumenta accesos a memoria y señala lecturas y escrituras concurrentes a la misma variable. Ejecutar tests con -race en CI permite detectar bugs que solo se manifiestan bajo condiciones de timing específicas.
Organización de Tests en Bases de Código Grandes
A medida que los proyectos crecen, la organización de tests afecta la mantenibilidad:
- Tests del mismo paquete (
package foo) acceden a funciones y campos no exportados. Se usan para tests unitarios que verifican comportamiento interno. - Tests de paquete externo (
package foo_test) importan el paquete como código externo. Se usan para tests de integración y para verificar la API pública. - Directorios testdata almacenan fixtures como archivos JSON, salidas de referencia o bases de datos de seed. Go los ignora durante los builds.
- Build tags separan tests unitarios de tests de integración que requieren sistemas externos. Ejecutar
go test -tags=integration ./...para incluirlos.
Para más información sobre buenas prácticas de Go más allá del testing, el artículo sobre patrones de concurrencia cubre goroutines y channels.
Puntos Clave sobre Testing en Go
- El paquete
testingviene incluido con Go y no requiere dependencias externas - Los tests basados en tablas reducen duplicación y son el patrón esperado en entrevistas
- Las interfaces permiten inyección de dependencias; deben definirse en el punto de uso, no en la implementación
gomockgenera mocks a partir de interfaces;testifyproporciona assertions más clarashttptest.ResponseRecordercaptura salida de handlers sin sobrecarga de red- El flag
-racedetecta bugs de concurrencia que los tests unitarios de otro modo no detectan - Las métricas de cobertura guían la atención pero no garantizan corrección
¡Empieza a practicar!
Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.
¿Sabrías detectar el bug en Go?
Un fragmento real, un bug oculto, un intento al día. Sin cuenta para probar.

Escrito por
Anthony Fillion-MailletFundador de SharpSkill
Desarrollador fullstack desde hace más de 10 años. Dirige SharpSkill y responde por todo lo que se publica aquí.
Actualizado el 24 de agosto de 2026
Etiquetas
Compartir
Artículos relacionados

El Paquete context de Go en 2026: Cancelación, Timeouts y Preguntas de Entrevista
Guía completa del paquete context de Go: gestión de cancelación, timeouts y deadlines. Incluye preguntas frecuentes de entrevistas técnicas y mejores prácticas de producción.

Interfaces Avanzadas en Go 2026: Composición, Aserciones de Tipo y Preguntas de Entrevista
Dominar la composición de interfaces en Go, aserciones de tipo y genéricos autorreferenciales de Go 1.26. Incluye ejemplos prácticos y preguntas de entrevista técnica.

Go SIMD y el Paquete ArchSIMD en 2026: Optimización de Rendimiento y Preguntas de Entrevista
Descubre el paquete simd/archsimd de Go 1.26: operaciones vectoriales nativas, optimización de rendimiento y preparación para entrevistas técnicas de Go.