Las pruebas son una parte fundamental del desarrollo de software, ya que aseguran que el código funcione como se espera y ayuda a prevenir errores en el futuro. En Go, las pruebas se escriben utilizando el paquete testing, que proporciona herramientas para crear y ejecutar pruebas unitarias, pruebas de integración y benchmarks.

Contenido

Introducción a las Pruebas en Go

Go tiene un soporte robusto para pruebas integrado en su herramienta de construcción. Las pruebas se escriben en archivos que terminan en _test.go y se colocan en el mismo paquete que el código que están probando.

Estructura de una Prueba

Una prueba en Go es una función que sigue la convención TestXxx y toma un parámetro de tipo *testing.T. Aquí hay un ejemplo básico:

package main

import (
    "testing"
)

func TestSum(t *testing.T) {
    total := Sum(5, 5)
    if total != 10 {
        t.Errorf("Sum was incorrect, got: %d, want: %d.", total, 10)
    }
}

En este ejemplo:

  • TestSum es el nombre de la función de prueba.
  • t *testing.T es el parámetro que se utiliza para reportar errores y fallos en la prueba.
  • t.Errorf se usa para reportar un error si la condición no se cumple.

Escribiendo Pruebas Unitarias

Las pruebas unitarias se centran en probar funciones individuales para asegurarse de que funcionan correctamente. Aquí hay un ejemplo más detallado:

Ejemplo de Función a Probar

Supongamos que tenemos una función Sum que suma dos números:

package main

func Sum(a int, b int) int {
    return a + b
}

Escribiendo la Prueba Unitaria

Ahora escribimos una prueba unitaria para esta función:

package main

import (
    "testing"
)

func TestSum(t *testing.T) {
    tests := []struct {
        name string
        a, b int
        want int
    }{
        {"positive numbers", 1, 2, 3},
        {"zero", 0, 0, 0},
        {"negative numbers", -1, -1, -2},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := Sum(tt.a, tt.b)
            if got != tt.want {
                t.Errorf("Sum(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want)
            }
        })
    }
}

En este ejemplo:

  • Usamos una tabla de pruebas para definir múltiples casos de prueba.
  • t.Run se usa para ejecutar cada caso de prueba individualmente.

Pruebas de Integración

Las pruebas de integración verifican que diferentes partes del sistema funcionen juntas correctamente. A menudo implican interacciones con bases de datos, servicios externos, etc.

Ejemplo de Prueba de Integración

Supongamos que tenemos una función que guarda datos en una base de datos:

package main

import (
    "database/sql"
    _ "github.com/lib/pq"
)

func SaveToDB(db *sql.DB, data string) error {
    _, err := db.Exec("INSERT INTO table_name (column_name) VALUES ($1)", data)
    return err
}

Escribiendo la Prueba de Integración

package main

import (
    "database/sql"
    "testing"
    _ "github.com/lib/pq"
)

func TestSaveToDB(t *testing.T) {
    db, err := sql.Open("postgres", "user=username dbname=mydb sslmode=disable")
    if err != nil {
        t.Fatal(err)
    }
    defer db.Close()

    err = SaveToDB(db, "testdata")
    if err != nil {
        t.Errorf("SaveToDB failed: %v", err)
    }
}

En este ejemplo:

  • sql.Open se usa para abrir una conexión a la base de datos.
  • t.Fatal se usa para detener la prueba si no se puede abrir la conexión.
  • t.Errorf se usa para reportar un error si la función SaveToDB falla.

Ejecutando Pruebas

Para ejecutar las pruebas, usa el comando go test en el directorio que contiene los archivos de prueba:

go test

Para obtener una salida más detallada, usa la bandera -v:

go test -v

Cobertura de Código

La cobertura de código mide qué porcentaje del código fuente es ejecutado durante las pruebas. Para generar un informe de cobertura, usa la bandera -cover:

go test -cover

Para generar un informe de cobertura detallado en un archivo, usa:

go test -coverprofile=coverage.out
go tool cover -html=coverage.out

Errores Comunes y Consejos

Errores Comunes

  1. No manejar errores correctamente: Asegúrate de verificar y manejar todos los errores en tus pruebas.
  2. Pruebas dependientes del entorno: Las pruebas deben ser independientes del entorno en el que se ejecutan.
  3. No limpiar después de las pruebas: Asegúrate de limpiar cualquier estado que tus pruebas puedan haber modificado.

Consejos

  1. Usa tablas de pruebas: Facilitan la adición de nuevos casos de prueba y mejoran la legibilidad.
  2. Pruebas paralelas: Usa t.Parallel() para ejecutar pruebas en paralelo y reducir el tiempo de ejecución.
  3. Mocks y stubs: Usa mocks y stubs para simular dependencias externas y hacer que las pruebas sean más rápidas y confiables.

Conclusión

En esta sección, hemos cubierto los conceptos básicos de las pruebas en Go, incluyendo cómo escribir pruebas unitarias y de integración, cómo ejecutar pruebas y cómo medir la cobertura de código. Las pruebas son esenciales para asegurar la calidad del software y deben ser una parte integral de tu flujo de trabajo de desarrollo. En el siguiente módulo, exploraremos el benchmarking para medir y optimizar el rendimiento de tu código.

© Copyright 2024. Todos los derechos reservados