testify, httptest y Test Doubles
Aserciones, pruebas de manejadores HTTP y mocks de interfaces.
Busca en todas las páginas de la documentación
Aserciones, pruebas de manejadores HTTP y mocks de interfaces.
La biblioteca estándar cubre la ejecución de pruebas y el registro de respuestas HTTP.
testify añade fallos de aserción legibles; httptest es la biblioteca estándar para manejadores; los test doubles en Go suelen ser fakes escritos a mano detrás de interfaces pequeñas.
Tarjeta de referencia rápida - lista para copiar y pegar.
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/require"
)
func TestHandler(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/health", nil)
rec := httptest.NewRecorder()
HealthHandler(rec, req)
require.Equal(t, http.StatusOK, rec.Code)
require.JSONEq(t, `{"status":"ok"}`, rec.Body.String())
}Cuándo recurrir a esto:
ListenAndServerequire detenga la configuración después de una precondición fallidapackage api
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var ErrNotFound = errors.New("not found")
type UserStore interface {
Get(ctx context.Context, id string) (string, error)
}
type fakeStore struct {
users map[string]string
}
func (f *fakeStore) Get(ctx context.Context, id string) (string, error) {
if name, ok := f.users[id]; ok {
return name, nil
}
return "", ErrNotFound
}
func UserHandler(store UserStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
name, err := store.Get(r.Context(), id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
_ = json.NewEncoder(w).Encode(map[string]string{"name": name})
}
}
func TestUserHandler(t *testing.T) {
store := &fakeStore{users: map[string]string{"1": "Ada"}}
srv := httptest.NewServer(UserHandler(store))
t.Cleanup(srv.Close)
resp, err := http.Get(srv.URL + "?id=1")
require.NoError(t, err)
defer resp.Body.Close()
require.Equal(t, http.StatusOK, resp.StatusCode)
var body map[string]string
require.NoError(t, json.NewDecoder(resp.Body).Decode(&body))
assert.Equal(t, "Ada", body["name"])
}Lo que esto demuestra:
fakeStore implementa UserStore sin un generador de mockshttptest.NewServer ejercita el comportamiento real de http.Clientt.Cleanup cierra el servidor después de la pruebarequire) de las comprobaciones adicionales (assert)httptest.NewRecorder implementa http.ResponseWriter en memoria.httptest.NewServer enlaza 127.0.0.1:0 y devuelve una URL lista para el cliente.reflect.DeepEqual y formatea las diferencias.| Herramienta | Inicia listener | Mejor para |
|---|---|---|
NewRecorder | No | Pruebas unitarias de funciones manejadoras |
NewServer | Sí (loopback) | Cadenas de middleware, TLS, tiempos de espera del cliente |
httptest.NewRequest | No | Construcción de *http.Request con contexto |
// gomock (opcional): go.uber.org/mock/mockgen
// Generar: mockgen -destination=mocks/store_mock.go . UserStoreLos fakes escritos a mano se mantienen legibles para uno o dos métodos; los generadores ayudan con interfaces amplias.
-count=100. Solución: defer resp.Body.Close() después de cada llamada al cliente.require.JSONEq o decodificar en structs.suite.Suite comparte campos entre pruebas. Solución: Preferir TestXxx simples con tablas a menos que los hooks sean esenciales.req = req.WithContext(ctx) en la configuración.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
if got != want simple | Cero dependencias, paquetes pequeños | Comparaciones de structs grandes |
cmp.Diff (google/go-cmp) | Diffs precisos de structs sin testify | El equipo ya está estandarizado en testify |
go.uber.org/mock | Interfaces amplias, muchas implementaciones | Fakes de un solo método |
| DB de docker real (testcontainers) | Verdad de integración SQL | Pruebas unitarias de mapeo JSON de manejadores |
No.
Muchas bases de código usan solo comprobaciones de la biblioteca estándar; testify es un módulo de conveniencia.
require llama a t.FailNow() - usar para precondiciones de configuración.
assert registra el fallo y continúa - usar para múltiples expectativas independientes.
Envuelve un manejador stub con tu middleware, pasa httptest.NewRecorder, y verifica el grabador.
Para pruebas de cadena completas, usa NewServer.
Sí - monta rutas en un http.Handler o llama a ServeHTTP del framework con un grabador.
Los objetos de contexto del framework pueden necesitar sus ayudantes de prueba.
Mantén los fakes pequeños en _test.go.
Mueve los fakes compartidos a export_test.go o a un paquete internal/testutil si muchos paquetes los reutilizan.
Añade campos en el struct fake (failNext bool, err error) que se alternan por fila de tabla.
Sí - cada subprueba obtiene su propio *testing.T.
Evita compartir fakes mutables entre subpruebas paralelas sin sincronización.
Usa bufconn con un listener en memoria o mocks generados para el stub del cliente.
Ver la sección grpc-protobuf para patrones.
Los archivos dorados bajo testdata/ son el snapshot idiomático de Go.
Los snapshots de testify son menos comunes que JSONEq más fixtures.
Sí, para código de cliente que llama a APIs externas - implementa RoundTrip en un fake.
Mantiene las pruebas sin conexión y deterministas.
rec.Header().Get("Content-Type") en un grabador, o resp.Header en respuestas del cliente.
Usa assert.ErrorIs y assert.ErrorAs - envuelven errors.Is / errors.As.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (Valor por defecto de GC Green Tea, go fix modernizers - verificar parche en la compilación), chi (última versión - verificar en la compilación), gin (última versión - verificar en la compilación), echo (última versión - verificar en la compilación), google.golang.org/grpc (última versión - verificar en la compilación), sigs.k8s.io/controller-runtime (última versión - verificar en la compilación), kubebuilder (última versión - verificar en la compilación), tinygo (última versión - verificar objetivos de placa en la compilación), wazero (última versión - verificar en la compilación) y golangci-lint (última versión - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 16 jul 2026