teste (testing) în Go

Comanda go, module și teste Go 1.0 (testing.B.Loop: Go 1.24)

Testele Go stau în fișiere _test.go, în funcții TestXxx(t *testing.T), și se rulează cu go test.

Sintaxă
// fisier_test.go, în același pachet
import "testing"

func TestNume(t *testing.T) { ... }
func BenchmarkNume(b *testing.B) { for b.Loop() { ... } }
func ExampleNume() { ... // Output: ... }

Ce face teste (testing)

Go are testarea integrată, fără biblioteci externe. Testele stau în fișiere care se termină cu _test.go, lângă codul testat. Fiecare test este o funcție func TestXxx(t *testing.T); dacă rezultatul nu este cel așteptat, testul raportează cu t.Errorf (continuă) sau t.Fatalf (se oprește). Fișierele _test.go nu intră în programul compilat cu go build.

Stilul obișnuit în Go este testul pe tabel: un slice de cazuri (intrare, rezultat așteptat) parcurs într-o buclă, fiecare caz rulat ca subtest cu t.Run(nume, ...). Funcțiile BenchmarkXxx(b *testing.B) măsoară viteza (rulate cu go test -bench .), iar funcțiile ExampleXxx cu un comentariu // Output: sunt în același timp teste și exemple în documentație.

Metodele lui testing.T (Error, Fatal, Run, Helper, Cleanup, TempDir, Parallel) au pagini proprii în secțiunea pachetului testing.

Exemple

Exemplul 1: Test pe tabel cu subteste

Fișierul preturi/preturi_test.go; rezultatul vine din go test -v ./preturi.

package preturi

import (
    "math"
    "testing"
)

func TestCuTVA(t *testing.T) {
    if got := CuTVA(100); math.Abs(got-121) > 1e-9 {
        t.Errorf("CuTVA(100) = %v, vreau 121", got)
    }
}

func TestReducere(t *testing.T) {
    cazuri := []struct {
        nume          string
        pret, procent float64
        vreau         float64
    }{
        {"fără reducere", 200, 0, 200},
        {"zece la sută", 200, 10, 180},
        {"jumătate", 50, 50, 25},
    }
    for _, c := range cazuri {
        t.Run(c.nume, func(t *testing.T) {
            if got := Reducere(c.pret, c.procent); math.Abs(got-c.vreau) > 1e-9 {
                t.Errorf("Reducere(%v, %v) = %v, vreau %v", c.pret, c.procent, got, c.vreau)
            }
        })
    }
}

Rezultat în terminal

=== RUN   TestCuTVA
--- PASS: TestCuTVA (0.00s)
=== RUN   TestReducere
=== RUN   TestReducere/fără_reducere
=== RUN   TestReducere/zece_la_sută
=== RUN   TestReducere/jumătate
--- PASS: TestReducere (0.00s)
    --- PASS: TestReducere/fără_reducere (0.00s)
    --- PASS: TestReducere/zece_la_sută (0.00s)
    --- PASS: TestReducere/jumătate (0.00s)
PASS
ok  	exemplu.ro/magazin/preturi	0.230s

Exemplul 2: Un test care eșuează

Am greșit formula în Reducere (procent/10 în loc de procent/100). Mesajul arată fișierul, rândul și cazurile care au picat.

go test ./preturi

Rezultat în terminal

--- FAIL: TestReducere (0.00s)
    --- FAIL: TestReducere/zece_la_sută (0.00s)
        preturi_test.go:27: Reducere(200, 10) = 0, vreau 180
    --- FAIL: TestReducere/jumătate (0.00s)
        preturi_test.go:27: Reducere(50, 50) = -200, vreau 25
FAIL
FAIL	exemplu.ro/magazin/preturi	0.289s
FAIL

Exemplul 3: Exemplu testabil și benchmark

go test verifică dacă ExampleCuTVA afișează exact textul din // Output:. b.Loop() (Go 1.24) repetă corpul de câte ori e nevoie pentru o măsurare stabilă.

// preturi/exemple_test.go
package preturi

import (
    "fmt"
    "testing"
)

func ExampleCuTVA() {
    fmt.Printf("%.2f\n", CuTVA(50))
    // Output: 60.50
}

func BenchmarkReducere(b *testing.B) {
    for b.Loop() {
        Reducere(199.99, 15)
    }
}

// în terminal:
// go test -bench . ./preturi

Rezultat în terminal

goos: darwin
goarch: arm64
pkg: exemplu.ro/magazin/preturi
cpu: Apple M1 Pro
BenchmarkReducere-10    	553138562	         2.257 ns/op
PASS
ok  	exemplu.ro/magazin/preturi	1.545s

Greșeli frecvente

  • Funcția de test scrisă Testreducere sau testReducere: după Test trebuie o majusculă, altfel nu este rulată (go vet avertizează).
  • Fișierul numit preturi_teste.go sau test_preturi.go: trebuie să se termine exact cu _test.go.
  • t.Fatal apelat dintr-o goroutine pornită de test: nu oprește testul corect; folosește t.Error și sincronizare.
  • Compararea numerelor reale cu == în teste: folosește o toleranță.

Comenzi înrudite

  • go test: Compilează și rulează testele (fișierele _test.go) și raportează ce a trecut și ce a picat.
  • module și pachete: Un pachet este un director cu fișiere .go; un modul (go.mod) este un proiect cu mai multe pachete și dependențele lor.
  • go vet: Analizează codul și semnalează greșeli probabile pe care compilatorul le acceptă: formate Printf greșite, copieri de mutex etc.