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.
gracias por el aporte, me arrojaba error por ello.
✨ Mini resumen
Ejecutar los test con la bandera -coverprofile=coverage.out para obtener un coverage. Esto nos permite saber que parte del código hemos testeado y cual no:
$ go test -coverprofile=coverage.out
Para tener las metricas legibles del resultado del coverage usamos:
// ver resumen resumen en la terminal$ go tool cover -func=coverage.out// o ver resumen en el navegador$ go tool cover -html=coverage.out
Esta clase es de las más valiosas del curso.
Muy buena la herramienta!!, ya para entornos un poco más productivos, la herramienta de Sonar nos puede ayudar también con el coverage!!!
Con la extensión oficial de go en VS Code se puede evidenciar el coverage también, solo se corren un test o los test de todo un package y te resalta con color verde lo que tienes cubierto, y rojo lo que falta por cubrir, súper útil para debuggear local también :D
Summary:
Code coverage
Test coverage is a measure used to describe the degree to which the source code of a program is executed when a particular test suite runs.
If the software you are testing contains a total of 100 lines of code and the number of lines of code that is actually validated in the same software is 50, then the code coverage percentage of this software will be 50 percent.
To test code coverage you can use:
$ go test -cover
If you wanted to, you could profile the coverage with:
$ go test -coverprofile=coverage.out # save it
$ go tool cover -func=coverage.out # make it more readable
$ go tool cover -html=coverage.out # or view it on the browser
package main
import"testing"func TestSum(t *testing.T){tables:=[]struct { x int
y int
r int
}{{1,2,3},{2,2,4},{3,2,5},{25,26,51},}for _,table:= range tables {total:=Sum(table.x, table.y)if total != table.r{ t.Errorf("Sum(%d, %d) was incorrect, got: %d, want: %d.", table.x, table.y, total, table.r)}}}func TestMax(t *testing.T){tables:=[]struct { x int
y int
r int
}{{1,2,2},{2,2,2},{3,2,3},{25,26,26},}for _,table:= range tables {max:=GetMax(table.x, table.y)if max != table.r{ t.Errorf("Max(%d, %d) was incorrect, got: %d, want: %d.", table.x, table.y, max, table.r)}}}
Buena clase, pero tengo una duda, como lo hago para excluir main() del code coverage?
ComandosIndicador de % cubriendo las pruebas
go test -cover // Nos indica el nivel de cobertura de as pruebas
Para generar el archivo cover
go test -coverprofile=coverage.out //Usamos este archivo para tener metricas de nuestras pruebas y saber que parte de nuetsro codigo no hay pruebas
ver resumen resumen en la terminal
go tool cover -func=coverage.out //Indicamos que le eviamos las funciones de nuetsro archivo main.go, lista las funciones
Ver resumen en el navegador
go tool cover -html=coverage.out //genera un html que puedes usar el navegador para validar los procesos o funciones que no se han evaluado
Al colocar el comando:
go test -coverprofile=coverage.out
Me aparece el siguiente mensaje y no crea ningún archivo coverage.out
no required module provides package.out; to add it: go
¿Cómo podría solucionar esto?
Aclaración: esto me pasa en un Windows 10.
Creo este enlace te puede caer de perlas… ¡Ánimos!
Clic
No puedo hacer nada porque cuando pruebo el test -cover obtengo un no statement
¿Me puedes ayudar a entender que sucede?
No me funcionó en html desde wsl
Por lo que entendí el comando usa el paquete xdg-open para abrir el navegador, pero no lo encuentra.
Entonces reinstalé el paquete
sudo apt-get install --reinstall xdg-util
Aún así no lo abre con el navegador, entonces tuve que agregar el navegador que está en Windows a las variables de entorno, en mi caso Google Chrome
Agregué esta línea al .bashrc
export BROWSER=/mnt/c/Program\ Files/Google/Chrome/Application/chrome.exe
Con esto ya me abre en el navegador pero no encuentra el archivo porque lo está buscando en el sistema de archivos de Windows y el archivo está en el sistema de archivos de Ubuntu.
Entonces tuve que modificar la url en el navegador
-- file:///tmp/cover1737959177/coverage.html++ file://wsl.localhost/Ubuntu/tmp/cover1737959177/coverage.html
Muy buena clase 🥸
a mi por algún motivo el -html=coverage.out no me funciona, no me lleva a la página web.
Para mac el comando coverage es el siguiente:
go test -v --cover
y los demás comandos de esta clase:
go test -coverprofile=cpverage.outgo tool cover -func=coverage.outgo tool cover -html=coverage.out
Muy interesante
😎
¿Cómo puedo ejecutar las pruebas que tenga en un subdirectorio por ejemplo tests/? siempre obtengo 0,0% coverage y errores similares
Es normal que los test se demoren tanto ?
esto es lo que tarde cuando hice es test
86.051s