Cobertura de código con pruebas en Go: de la "marca verde" a la calidad real
\n\nEn el mundo del desarrollo en Go, la frase "tengo un 95% de cobertura" suena orgullosa. Pero a menudo detrás de esta cifra se esconde el vacío: las pruebas solo verifican el camino feliz, mientras que los casos límite y los errores quedan fuera. En este artículo, analizaremos cómo medir la cobertura de código con pruebas en Go de verdad, qué métricas son realmente importantes y qué herramientas ayudarán a convertir las pruebas de una formalidad en una poderosa herramienta de control de calidad.
\n\nNo vamos a repetir la documentación. En su lugar, ofrecemos ejemplos reales, trampas y consejos prácticos para quienes escriben en Go y quieren dormir tranquilos.
\n\n¿Por qué simplemente un 80% es malo?
\n\nSupongamos que tienes una función:
\n\nfunc ProcessOrder(amount float64, discount bool) (float64, error) {\n if amount <= 0 {\n return 0, errors.New("amount must be positive")\n }\n if discount {\n amount *= 0.9\n }\n return amount, nil\n}\n\nEscribiste una prueba: ProcessOrder(100, true) → 90, nil. ¿Cobertura? 100% de las líneas. Pero no verificaste el caso con amount <= 0 ni el caso sin descuento. Formalmente, la cobertura es excelente. En realidad, los errores están garantizados. Por eso, las métricas de cobertura de código con pruebas en Go deben considerarse junto con otros indicadores.
Herramientas de cobertura: de lo simple a lo complejo
\n\n1. go test -cover integrado
\n\nLa forma más sencilla de conocer la cobertura de código con pruebas en Go es la bandera -cover:
go test -cover ./...\n\nSalida:
\nok myproject/orders 0.234s coverage: 72.3% of statements\n\nPero esto es solo una cifra general. Para ver qué líneas no están cubiertas, usa -coverprofile:
go test -coverprofile=coverage.out ./...\ngo tool cover -html=coverage.out\n\nSe abrirá un navegador con resaltado: verde significa cubierto, rojo significa no cubierto. Este es el primer paso para comprender las métricas de cobertura de Go.
\n\n2. go tool cover: modos y matices
\n\ngo tool cover admite tres modos:
- \n
- set — si la línea se ejecutó al menos una vez (por defecto) \n
- count — cuántas veces se ejecutó cada línea \n
- atomic — count, pero con contadores atómicos para pruebas paralelas \n
Para el análisis de cobertura de pruebas en Golang en código multiproceso, usa atomic, de lo contrario corres el riesgo de obtener contadores incorrectos debido a condiciones de carrera.
\n\ngo test -covermode=atomic -coverprofile=coverage.out ./...\n\n3. Race detector: cobertura oculta
\n\nLas condiciones de carrera son uno de los principales problemas del código Go. Incluso si la cobertura de líneas es del 100%, el race detector puede encontrar errores que las pruebas no detectaron. Ejecuta las pruebas con la bandera -race:
go test -race -cover ./...\n\nImportante: el race detector ralentiza las pruebas de 2 a 20 veces, pero para módulos críticos es una práctica obligatoria. Inclúyelo en tu CI para paquetes clave.
\n\nMétricas que realmente importan
\n\nEl porcentaje de cobertura de líneas es solo la punta del iceberg. Esto es lo que debes rastrear:
\n\n1. Cobertura de ramificaciones (branch coverage)
\n\nEl go test -cover estándar cuenta líneas, no ramas. Para la cobertura de código con pruebas en Go a nivel de ramificaciones, usa gocov o go-test-coverage. Ejemplo:
go get github.com/axw/gocov/gocov\ngocov test ./... | gocov report\n\nVerás no solo las líneas, sino también la cantidad de condiciones no cubiertas. Por ejemplo, para una función con dos if, hay 4 ramas, de las cuales solo 2 están cubiertas.
\n\n2. Cobertura por mutaciones (mutation testing)
\n\nLa forma más honesta de evaluar la calidad de las pruebas es