Las pruebas unitarias son una parte importante de la escritura
de programas en Go con principios. El paquete testing
proporciona las herramientas que necesitamos para escribir pruebas unitarias
y el comando go test ejecuta las pruebas.
|
|
A modo de demostración, este código está en el paquete
main , pero podría ser cualquier paquete. El código de prueba
típicamente vive en el mismo paquete que el código que prueba.
|
package main
|
|
import (
"fmt"
"testing"
)
|
Vamos a probar esta simple implementación de un mínimo
entero. Típicamente, el código que estamos probando
estaría en un archivo fuente llamado algo así como
intutils.go , y el archivo de prueba para él se llamaría entonces
intutils_test.go .
|
func IntMin(a, b int) int {
if a < b {
return a
}
return b
}
|
Una prueba se crea escribiendo una función con un nombre
que comienza con Test .
|
func TestIntMinBasic(t *testing.T) {
ans := IntMin(2, -2)
if ans != -2 {
|
t.Error* informará de fallos en las pruebas pero continuará
ejecutando la prueba. t.Fatal* informará de fallos en las pruebas y detendrá la prueba
inmediatamente.
|
t.Errorf("IntMin(2, -2) = %d; want -2", ans)
}
}
|
Escribir pruebas puede ser repetitivo, por lo que es idiomático
usar un estilo basado en tablas, donde las entradas de prueba y
los resultados esperados se enumeran en una tabla y un solo bucle
las recorre y realiza la lógica de la prueba.
|
func TestIntMinTableDriven(t *testing.T) {
var tests = []struct {
a, b int
want int
}{
{0, 1, 0},
{1, 0, 0},
{2, -2, -2},
{0, -1, -1},
{-1, 0, -1},
}
|
t.Run permite ejecutar “subpruebas”, una para cada
entrada de la tabla. Estas se muestran por separado
al ejecutar go test -v .
|
for _, tt := range tests {
|
|
testname := fmt.Sprintf("%d,%d", tt.a, tt.b)
t.Run(testname, func(t *testing.T) {
ans := IntMin(tt.a, tt.b)
if ans != tt.want {
t.Errorf("got %d, want %d", ans, tt.want)
}
})
}
}
|
Las pruebas de rendimiento típicamente van en archivos _test.go y están
nombradas comenzando con Benchmark . El ejecutor de testing
ejecuta cada función de rendimiento varias veces, aumentando
b.N en cada ejecución hasta que recopila una medición precisa.
|
func BenchmarkIntMin(b *testing.B) {
|
Normalmente, la prueba de rendimiento ejecuta una función que estamos
evaluando en un bucle b.N veces.
|
for i := 0; i < b.N; i++ {
IntMin(1, 2)
}
}
|
Ejecuta todas las pruebas en el proyecto actual en modo detallado.
|
$ go test -v
== RUN TestIntMinBasic
--- PASS: TestIntMinBasic (0.00s)
=== RUN TestIntMinTableDriven
=== RUN TestIntMinTableDriven/0,1
=== RUN TestIntMinTableDriven/1,0
=== RUN TestIntMinTableDriven/2,-2
=== RUN TestIntMinTableDriven/0,-1
=== RUN TestIntMinTableDriven/-1,0
--- PASS: TestIntMinTableDriven (0.00s)
--- PASS: TestIntMinTableDriven/0,1 (0.00s)
--- PASS: TestIntMinTableDriven/1,0 (0.00s)
--- PASS: TestIntMinTableDriven/2,-2 (0.00s)
--- PASS: TestIntMinTableDriven/0,-1 (0.00s)
--- PASS: TestIntMinTableDriven/-1,0 (0.00s)
PASS
ok examples/testing-and-benchmarking 0.023s
|
Ejecuta todas las pruebas de rendimiento en el proyecto actual. Todas las pruebas
se ejecutan antes de las pruebas de rendimiento. La bandera bench filtra
los nombres de las funciones de rendimiento con una expresión regular.
|
$ go test -bench=.
goos: darwin
goarch: arm64
pkg: examples/testing
BenchmarkIntMin-8 1000000000 0.3136 ns/op
PASS
ok examples/testing-and-benchmarking 0.351s
|