Nouveau : Datasets open source gratuits disponibles !Decouvrir →
🧪
Intermediaire 25 min Go

Tester Go avec Go Test

Pourquoi Tester Go avec Go Test ?

Tester est un aspect crucial dans le développement logiciel, et Go propose une solution native pour tester ses programmes, nommée Go Test. Ce processus de test aide à vérifier que votre code fonctionne correctement, permet une refactoring plus sûre, et contribue à la qualité globale du projet. Dans le contexte réel, un développeur doit tester chaque partie de son application pour s'assurer qu'elle répond aux exigences des utilisateurs et est robuste face aux anomalies.

Un cas d'utilisation concret serait de tester une fonction qui effectue un calcul mathématique complexe. Sans tests, il y aurait un risque significatif que le résultat soit incorrect ou que le code ne fonctionne pas comme prévu dans certaines conditions.

Prerequis

  • Connaissance des bases de Go
  • Installation de Go (version 1.16 ou ultérieure)
  • Un éditeur de texte pour écrire et exécuter le code Go

Concepts fondamentaux

1. Structure d'un Test en Go

En Go, un test est simplement une fonction qui commence par Test suivi du nom de la fonction à tester. Elle prend un paramètre t *testing.T, qui contient des méthodes pour signaler les erreurs.

// Importation du package testing
import "testing"

// Fonction à tester
func Add(a, b int) int {
    return a + b
}

// Test de la fonction Add
func TestAdd(t *testing.T) {
    if result := Add(2, 3); result != 5 {
        t.Errorf("Add(2, 3) = %d; want 5", result)
    }
}

2. Tableau de Tests

Les tests par tableau permettent de tester plusieurs cas d'usage en une seule fonction.

// Fonction à tester
func Multiply(a, b int) int {
    return a * b
}

// Test de la fonction Multiply avec tableau de tests
func TestMultiply(t *testing.T) {
    testCases := []struct {
        a, b, expected int
    }{
        {2, 3, 6},
        {-1, -1, 1},
        {0, 5, 0},
    }

    for _, tc := range testCases {
        if result := Multiply(tc.a, tc.b); result != tc.expected {
            t.Errorf("Multiply(%d, %d) = %d; want %d", tc.a, tc.b, result, tc.expected)
        }
    }
}

3. Tests de Benchmarks

Les benchmarks permettent d'évaluer la performance de votre code.

// Fonction à benchmark
func Sum(numbers []int) int {
    sum := 0
    for _, num := range numbers {
        sum += num
    }
    return sum
}

// Benchmark de la fonction Sum
func BenchmarkSum(b *testing.B) {
    numbers := make([]int, 1000)
    for i := range numbers {
        numbers[i] = i
    }

    for n := 0; n < b.N; n++ {
        Sum(numbers)
    }
}

4. Tests de Benchmark Concurrents

Les benchmarks concurrents permettent d'évaluer la performance des fonctions sous charge.

// Fonction à benchmark concurrent
func ParallelSum(numbers []int) int {
    sum := 0
    for _, num := range numbers {
        sum += num
    }
    return sum
}

// Benchmark concurrent de la fonction ParallelSum
func BenchmarkParallelSum(b *testing.B) {
    b.RunParallel(func(pb *testing.PB) {
        numbers := make([]int, 1000)
        for i := range numbers {
            numbers[i] = i
        }

        for pb.Next() {
            ParallelSum(numbers)
        }
    })
}

5. Tests de Benchmark des Fonctions Répétitives

Les benchmarks répétitifs permettent d'évaluer la performance des fonctions avec un grand nombre d'itérations.

// Fonction à benchmark répétitive
func RepeatString(s string, n int) string {
    result := ""
    for i := 0; i < n; i++ {
        result += s
    }
    return result
}

// Benchmark répétitif de la fonction RepeatString
func BenchmarkRepeatString(b *testing.B) {
    b.Run("5", func(b *testing.B) {
        b.ReportAllocs()
        for n := 0; n < b.N; n++ {
            RepeatString("a", 5)
        }
    })

    b.Run("10", func(b *testing.B) {
        b.ReportAllocs()
        for n := 0; n < b.N; n++ {
            RepeatString("a", 10)
        }
    })
}

Mise en pratique : projet fil rouge

Nous allons créer un simple gestionnaire de tâches (todo list) en Go. Le projet comprendra des fonctions pour ajouter, supprimer et afficher les tâches.

Étape 1 : Initialisation du Projet

mkdir todoapp
cd todoapp
go mod init todoapp

Étape 2 : Création des Fichiers

Créons trois fichiers : task.go, todo.go, et main_test.go.

task.go

// task.go
package main

import (
    "errors"
)

type Task struct {
    ID   int
    Desc string
}

var tasks = []Task{}

func GetTasks() []Task {
    return tasks
}

func AddTask(desc string) (int, error) {
    if desc == "" {
        return 0, errors.New("Description cannot be empty")
    }

    id := len(tasks) + 1
    task := Task{ID: id, Desc: desc}
    tasks = append(tasks, task)
    return id, nil
}

func RemoveTask(id int) error {
    for i, task := range tasks {
        if task.ID == id {
            tasks = append(tasks[:i], tasks[i+1:]...)
            return nil
        }
    }
    return errors.New("Task not found")
}

todo.go

// todo.go
package main

import "fmt"

func PrintTasks() {
    for _, task := range GetTasks() {
        fmt.Printf("ID: %d, Description: %s\n", task.ID, task.Desc)
    }
}

main_test.go

// main_test.go
package main

import (
    "testing"
)

func TestAddTask(t *testing.T) {
    _, err := AddTask("Buy groceries")
    if err != nil {
        t.Errorf("AddTask() error = %v; want nil", err)
    }

    tasks := GetTasks()
    if len(tasks) != 1 {
        t.Errorf("len(GetTasks()) = %d; want 1", len(tasks))
    }
}

func TestRemoveTask(t *testing.T) {
    id, _ := AddTask("Buy groceries")
    RemoveTask(id)

    tasks := GetTasks()
    if len(tasks) != 0 {
        t.Errorf("len(GetTasks()) = %d; want 0", len(tasks))
    }
}

Étape 3 : Exécution des Tests

go test

Erreurs frequentes et debugging

  1. Erreur : undefined: AddTask

    # ❌ Mauvais
    _, err := AddTask("Buy groceries")
    if err != nil {
        t.Errorf("AddTask() error = %v; want nil", err)
    }
    
    # ✅ Correct
    id, _ := AddTask("Buy groceries")
    if id == 0 {
        t.Errorf("AddTask() returned ID = %d; want a valid ID", id)
    }
    
  2. Erreur : len(GetTasks()) = 1; want 1

    # ❌ Mauvais
    tasks := GetTasks()
    if len(tasks) != 1 {
        t.Errorf("len(GetTasks()) = %d; want 1", len(tasks))
    }
    
    # ✅ Correct
    tasks := GetTasks()
    if len(tasks) == 0 {
        t.Errorf("len(GetTasks()) = %d; want at least one task", len(tasks))
    }
    
  3. Erreur : RemoveTask() error = Task not found; want nil

    # ❌ Mauvais
    RemoveTask(1)
    tasks := GetTasks()
    if len(tasks) != 0 {
        t.Errorf("len(GetTasks()) = %d; want 0", len(tasks))
    }
    
    # ✅ Correct
    id, _ := AddTask("Buy groceries")
    RemoveTask(id)
    tasks := GetTasks()
    if len(tasks) == 1 {
        t.Errorf("len(GetTasks()) = %d; want 0", len(tasks))
    }
    

Pour aller plus loin

  1. Test de Couverture : Apprenez à mesurer la couverture des tests avec go test -cover.

  2. Tests Asynchrones : Découvrez comment tester des fonctions asynchrones en utilisant t.Run pour créer des sous-tests.

  3. Mocking : Utilisez le package mockery pour créer des mocks de dépendances lors de l'écriture de tests unitaires.

Défi pratique

Créez un test pour une fonction qui prend une liste de nombres et retourne la somme des cubes de ces nombres. Assurez-vous que vous couvrez tous les cas d'usage, y compris le cas où la liste est vide.

Besoin d'aide sur Go ?

Besoin d'aide sur un projet technique ? Decrivez-le pour des conseils personnalises.

Recevoir des conseils

Questions frequentes

Qu'est-ce que 'go test' et pourquoi est-il utile ?
'Go Test' est une commande Go qui permet d'exécuter des tests unitaires pour les paquets spécifiés. Il est utile pour s'assurer que le code fonctionne correctement et pour prévenir les erreurs de régression lors des modifications.
Comment créer un fichier de test dans Go ?
Pour créer un fichier de test en Go, il suffit de nommer le fichier avec la même racine que le paquet mais en ajoutant '_test' avant l'extension '.go'. Par exemple, si vous avez un fichier 'calculator.go', votre fichier de test sera nommé 'calculator_test.go'.
Quelle est la syntaxe pour écrire une fonction de test en Go ?
Une fonction de test en Go doit être préfixée par le mot-clé 'Test' et accepter deux paramètres : un pointeur sur *testing.T et une chaîne de caractères. Par exemple, `func TestAdd(t *testing.T) { ... }`.

Pages liees

Chaque semaine, le meilleur de la tech francaise

Tendances, salaires, outils et opportunites — directement dans votre boite mail.

Gratuit. Desabonnement en un clic. Pas de spam.