DMarlon Studio

Lección 18 · 18 de 20

Comprobaciones con tablas · Go

Compruebe una función en Go con una tabla de casos, como en los tests de go test: cada caso con nombre, entrada y resultado esperado.

Go · Comprobaciones con tablas en DMarlon Studio: el código del ejemplo y su salida en la terminal

En Go, la forma más común de probar una función es una tabla de casos: un slice de structs con un nombre, la entrada y el resultado esperado. tests es un slice de un struct anónimo, declarado ahí mismo porque no se usa en ningún otro sitio.

La función que se prueba es shipping: los pedidos de 50,00 EUR o más no pagan el envío y el resto paga 4,95. Los importes van en céntimos (5000 son 50,00 EUR) para comparar enteros y no decimales, que pueden no coincidir por redondeo.

El bucle llama a shipping con cada total, compara lo obtenido (got) con lo esperado (want) y escribe ok o FAIL. Si falla, el mensaje dice qué se llamó, qué salió y qué debía salir: con eso suele bastar para encontrar el error sin depurar. failed cuenta los fallos para el resumen final.

Y hay uno: exactly 50.00 espera 0 pero obtiene 495, porque la condición es total > 5000 y debería ser >=. Es el error más típico, el del límite, y por eso conviene probar siempre los bordes: un céntimo menos (4999), justo el límite (5000) y el caso vacío (0).

En un proyecto, esta misma tabla va en un fichero shipping_test.go, dentro de func TestShipping(t *testing.T); cada caso se ejecuta con t.Run(tc.name, ...), el fallo se informa con t.Errorf y todo se lanza con go test. Añadir un caso es añadir una línea.

Código · main.go

package mainimport "fmt"// shipping returns the delivery cost in cents: orders from 50.00 ship free.func shipping(total int) int {	if total > 5000 { // bug: an order of exactly 50.00 should also ship free		return 0	}	return 495}func main() {	tests := []struct {		name        string		total, want int // in cents	}{		{"small order", 2000, 495},		{"one cent short", 4999, 495},		{"exactly 50.00", 5000, 0},		{"large order", 12000, 0},		{"empty cart", 0, 495},	}	failed := 0	for _, tc := range tests {		got := shipping(tc.total)		status := "ok  "		if got != tc.want {			status, failed = "FAIL", failed+1		}		fmt.Printf("%s %-15s shipping(%5d) = %3d, want %3d\n", status, tc.name, tc.total, got, tc.want)	}	fmt.Printf("%d passed, %d failed\n", len(tests)-failed, failed)}

Salida · go run main.go

ok   small order     shipping( 2000) = 495, want 495
ok   one cent short  shipping( 4999) = 495, want 495
FAIL exactly 50.00   shipping( 5000) = 495, want   0
ok   large order     shipping(12000) =   0, want   0
ok   empty cart      shipping(    0) = 495, want 495
4 passed, 1 failed

Para recordar

  • Una tabla de casos es un slice de structs: nombre, entrada y esperado.
  • Compare got con want y diga ambos cuando falle.
  • Pruebe los bordes: justo el límite, uno menos y el vacío.
  • Con dinero, compare enteros en céntimos.
  • En go test, la misma tabla con t.Run y t.Errorf.

Ejercicio

Corrija el error cambiando > por >= y compruebe que pasan los cinco casos. Después añada un parámetro express bool que sume 6,00 EUR siempre, y amplíe la tabla con dos casos urgentes.