Saber qué partes de tu código no están siendo probadas es tan importante como escribir los propios tests. El code coverage es la métrica que te permite identificar exactamente qué funciones, condiciones y líneas carecen de pruebas, ayudándote a evaluar la salud y calidad de tu proyecto. A continuación, se explica paso a paso cómo utilizar las herramientas nativas de Go para medir, visualizar y mejorar esa cobertura.
¿Cómo se mide el code coverage con Go? [01:10]
Go incluye opciones integradas para conocer el porcentaje de código cubierto por tests. El primer comando útil es:
bash
go test -cover
Este comando ejecuta los tests y muestra un porcentaje general de cobertura. En el ejemplo práctico, la función Sum ya tenía tests, pero GetMax no contaba con ninguno, lo que arrojaba apenas un 25% de cobertura [01:22].
Para obtener información más detallada, se genera un archivo de perfil de cobertura con:
bash
go test -coverprofile=coverage.out
Este archivo contiene datos en bruto que no son fáciles de leer directamente. Por eso se utiliza la herramienta cover para transformarlos en un resumen legible [02:08]:
bash
go tool cover -func=coverage.out
El resultado muestra función por función el porcentaje cubierto. En este caso, Sum aparecía al 100% y GetMax al 0%.
¿Cómo visualizar la cobertura en HTML? [02:55]
Go ofrece una forma visual muy clara de identificar código sin testear. Con el siguiente comando se genera un reporte HTML:
bash
go tool cover -html=coverage.out
Esto abre una pestaña en el navegador donde:
El código en color verde representa las líneas correctamente testeadas.
El código en color rojo señala las líneas sin ninguna prueba.
En el ejemplo, toda la función GetMax aparecía en rojo, dejando claro que necesitaba tests de forma urgente [03:18].
¿Qué pasa cuando los tests no cubren todas las condiciones? [03:42]
Agregar un test no garantiza cobertura completa. Aquí se creó un test para GetMax utilizando table-driven tests, una técnica donde se definen múltiples casos en una estructura y se iteran automáticamente:
go
func TestMax(t *testing.T) {
tables := []struct {
a int
b int
n int
}{
{4, 1, 4},
{3, 2, 3},
}
for _,item:= range tables {max:=GetMax(item.a, item.b)if max != item.n{ t.Errorf("GetMax fue incorrecto, obtuvimos %d, esperábamos %d", max, item.n)}}
}
El detalle importante es que todos los casos tenían el primer número mayor que el segundo de forma intencional [04:20]. Los tests pasaron correctamente y la cobertura subió al 75%, pero no al 100%.
¿Por qué no se alcanzó el 100% de cobertura?
Al regenerar el reporte HTML, se observó que solo uno de los dos return statements de GetMax estaba cubierto [05:45]. La función tiene una condición if que evalúa cuál número es mayor:
Si el primero es mayor, retorna el primero (cubierto en verde).
Si el segundo es mayor, retorna el segundo (en rojo, sin cubrir).
Como todos los casos de prueba seguían el mismo camino lógico, el segundo branch nunca se ejecutó. Esto demuestra que la cobertura por condiciones (branch coverage) es tan relevante como la cobertura por funciones.
¿Cómo se logró el 100% de cobertura? [06:20]
La solución fue agregar un caso donde el segundo número fuera mayor que el primero. Tras modificar la tabla de tests, se regeneró el reporte y se confirmó un 100% de cobertura.
Este resultado implica que cada línea y cada rama condicional del código fue ejercitada por al menos un test.
¿Por qué importa la cobertura de tests?
Un porcentaje bajo de code coverage debe ser una señal de alerta. Las funciones sin tests pueden ocultar errores que solo se manifiestan en producción. Algunos puntos clave:
Mayor cobertura equivale a mayor confianza en el comportamiento del código.
Las herramientas de Go (-cover, -coverprofile, go tool cover) son nativas y no requieren dependencias externas.
Visualizar la cobertura en HTML facilita la detección rápida de código descubierto.
Los table-driven tests permiten escalar casos de prueba de forma ordenada y legible.
Si te quedaron dudas o quieres compartir tus propios resultados de cobertura, deja tu comentario.