Go Testing 2026: Unit Tests, Mocks en Technische Sollicitatievragen
Een uitgebreide gids over Go-testpraktijken in 2026, inclusief unit tests met het testing-pakket, mocking met gomock en veelgestelde sollicitatievragen over Go-testen.

Go testing is gebaseerd op het standaard testing-pakket, dat wordt meegeleverd met elke Go-installatie en geen externe afhankelijkheden vereist. In tegenstelling tot frameworks in andere talen geeft Go de voorkeur aan eenvoud: testbestanden bevinden zich naast de productiecode, testfuncties volgen een naamgevingsconventie, en het go test-commando regelt de detectie en uitvoering.
Kandidaten die table-driven tests schrijven, interfaces gebruiken voor dependency injection en begrijpen wanneer mocking waarde toevoegt versus wanneer het alleen maar ruis veroorzaakt.
Unit Tests schrijven met het testing-pakket
Elk testbestand eindigt met _test.go en bevindt zich in hetzelfde package als de te testen code. Testfuncties beginnen met Test gevolgd door een naam met een hoofdletter. De *testing.T-parameter biedt methoden voor het rapporteren van fouten.
package calculator
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("Add(2, 3) = %d; want 5", result)
}
}Het uitvoeren van go test ./... voert alle tests in de huidige module uit. De -v-vlag toont individuele testnamen en hun geslaagd/gefaald-status.
Table-Driven Tests: De Go-Standaard
Table-driven tests verminderen duplicatie en maken het toevoegen van nieuwe cases triviaal. Elke rij in de tabel vertegenwoordigt een scenario met inputs en verwachte outputs. Dit patroon komt voor in de Go standaardbibliotheek en in productiecodebases in de hele industrie.
package validator
import "testing"
func TestValidateEmail(t *testing.T) {
tests := []struct {
name string
email string
wantErr bool
}{
{"valid email", "user@example.com", false},
{"missing at sign", "userexample.com", true},
{"empty string", "", true},
{"unicode local part", "user@例え.jp", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateEmail(tt.email)
if (err != nil) != tt.wantErr {
t.Errorf("ValidateEmail(%q) error = %v, wantErr %v",
tt.email, err, tt.wantErr)
}
})
}
}De t.Run-methode maakt subtests die onafhankelijk van elkaar draaien. Gefaalde subtests rapporteren welke specifieke case is gefaald zonder andere cases te stoppen.
Dependency Injection via Interfaces
Go interfaces maken het mogelijk om code te testen die afhankelijk is van externe systemen: databases, HTTP-clients, bestandssystemen. Het definiëren van een minimale interface op het punt van gebruik maakt het mogelijk om echte implementaties te vervangen door test doubles.
package order
// Repository definieert de data access methoden die deze service nodig heeft
type Repository interface {
FindByID(id string) (*Order, error)
Save(order *Order) error
}
// Service behandelt de order business logic
type Service struct {
repo Repository
}
// NewService maakt een service met de gegeven repository
func NewService(repo Repository) *Service {
return &Service{repo: repo}
}
// Process valideert en slaat een order op
func (s *Service) Process(order *Order) error {
if order.Total <= 0 {
return ErrInvalidTotal
}
return s.repo.Save(order)
}De Service accepteert elk type dat voldoet aan Repository. Productiecode geeft een database-backed implementatie door. Tests geven een mock of stub door.
Mocking met gomock en mockgen
Het gomock-pakket genereert mock-implementaties vanuit interface-definities. Het mockgen-commando leest bronbestanden en produceert mock-structs die aanroepen registreren en geconfigureerde waarden retourneren.
# Genereer mocks voor de Repository interface
mockgen -source=service.go -destination=mocks/repository_mock.go -package=mocksGebruik van de gegenereerde mock in tests:
package order
import (
"testing"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"yourmodule/order/mocks"
)
func TestService_Process_SavesValidOrder(t *testing.T) {
ctrl := gomock.NewController(t)
mockRepo := mocks.NewMockRepository(ctrl)
order := &Order{ID: "123", Total: 99.99}
// Verwacht dat Save eenmaal wordt aangeroepen met deze order, retourneer nil
mockRepo.EXPECT().
Save(order).
Return(nil).
Times(1)
svc := NewService(mockRepo)
err := svc.Process(order)
assert.NoError(t, err)
}
func TestService_Process_RejectsZeroTotal(t *testing.T) {
ctrl := gomock.NewController(t)
mockRepo := mocks.NewMockRepository(ctrl)
// Geen aanroepen naar repo verwacht omdat validatie eerst faalt
svc := NewService(mockRepo)
err := svc.Process(&Order{ID: "456", Total: 0})
assert.ErrorIs(t, err, ErrInvalidTotal)
}De mock verifieert dat Save precies eenmaal is aangeroepen met het verwachte argument. Als de te testen code Save nooit aanroept, of het aanroept met andere argumenten, faalt de test.
Testify gebruiken voor Assertions en Suites
testify biedt assertion-functies die duidelijkere foutmeldingen produceren dan handmatige if-checks. Het assert-pakket gaat door met uitvoering na fouten. Het require-pakket stopt de test onmiddellijk.
package user
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestParseUser(t *testing.T) {
input := `{"id": "u1", "name": "Alice"}`
user, err := ParseUser(input)
require.NoError(t, err, "parsing should not fail")
assert.Equal(t, "u1", user.ID)
assert.Equal(t, "Alice", user.Name)
assert.Empty(t, user.Email, "email should default to empty")
}De require.NoError-aanroep stopt de test als parsing faalt, waardoor nil pointer panics bij volgende assertions worden voorkomen.
Klaar om je Go gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
HTTP Handlers testen met httptest
Het net/http/httptest-pakket biedt ResponseRecorder voor het vastleggen van handler-output en Server voor het draaien van een lokale testserver. De meeste unit tests gebruiken ResponseRecorder om network overhead te vermijden.
package api
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestHealthHandler(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/health", nil)
rec := httptest.NewRecorder()
HealthHandler(rec, req)
assert.Equal(t, http.StatusOK, rec.Code)
assert.JSONEq(t, `{"status": "ok"}`, rec.Body.String())
}Voor handlers die externe services aanroepen, wordt een mock-client geïnjecteerd of wordt httptest.NewServer gebruikt om een fake backend te maken.
Veelgestelde Sollicitatievragen over Go Testing
Interviewers beoordelen testkennis door vragen die ervaring met echte codebases onthullen. Hier zijn patronen die voorbereide kandidaten onderscheiden:
"Hoe zou je een functie testen die een externe API aanroept?"
Definieer een interface voor de HTTP-client, injecteer deze in de functie of struct, en voorzie een mock die vooraf bepaalde responses retourneert. Dit vermijdt netwerkaanroepen en maakt tests deterministisch.
"Wanneer zou je een stub versus een mock gebruiken?"
Stubs retourneren standaard responses zonder te verifiëren hoe ze werden aangeroepen. Mocks verifiëren dat specifieke methoden werden aangeroepen met specifieke argumenten. Gebruik stubs wanneer de retourwaarde belangrijker is dan de interactie. Gebruik mocks wanneer het verifiëren van de interactie het doel van de test is.
"Wat zijn table-driven tests en waarom geeft Go er de voorkeur aan?"
Table-driven tests definiëren testcases als data in een slice van structs. Ze verminderen boilerplate, maken het toevoegen van cases triviaal en produceren leesbare testoutput met t.Run. Het patroon sluit aan bij Go's voorkeur voor expliciete, repetitieve code boven slimme abstracties.
"Hoe ga je om met test fixtures of setup die meerdere tests delen?"
Gebruik TestMain voor setup en teardown op package-niveau. Gebruik helperfuncties of test suites (van testify) voor gedeelde setup over gerelateerde tests. Vermijd globale state die koppeling tussen tests creëert.
Voorbereiden op een Go-sollicitatiegesprek? De Go Testing module behandelt deze patronen uitgebreid met oefenvragen.
Tests uitvoeren met Coverage en Race Detection
Het go test-commando accepteert vlaggen die ongeteste codepaden en concurrency-bugs onthullen.
# Tests uitvoeren met coverage rapport
go test -cover ./...
# HTML coverage visualisatie genereren
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# Race conditions detecteren (langzamer, maar vindt echte bugs)
go test -race ./...De race detector instrumenteert geheugentoegangen en signaleert gelijktijdige reads en writes naar dezelfde variabele. Het uitvoeren van tests met -race in CI vangt bugs die zich alleen onder specifieke timing manifesteren.
Tests organiseren in Grote Codebases
Naarmate projecten groeien, beïnvloedt testorganisatie de onderhoudbaarheid:
- Same-package tests (
package foo) hebben toegang tot niet-geëxporteerde functies en velden. Gebruik voor unit tests die intern gedrag verifiëren. - External-package tests (
package foo_test) importeren het package als externe code. Gebruik voor integratietests en om de publieke API te verifiëren. - Testdata directories slaan fixtures op zoals JSON-bestanden, golden outputs of seed databases. Go negeert deze tijdens builds.
- Build tags scheiden unit tests van integratietests die externe systemen vereisen. Voer
go test -tags=integration ./...uit om ze op te nemen.
Voor meer Go best practices buiten testing, behandelt het artikel over concurrency patronen goroutines en channels.
Wat te onthouden over Go Testing
- Het
testing-pakket wordt meegeleverd met Go en vereist geen externe afhankelijkheden - Table-driven tests verminderen duplicatie en zijn het verwachte patroon in sollicitatiegesprekken
- Interfaces maken dependency injection mogelijk; definieer ze op het punt van gebruik, niet bij de implementatie
gomockgenereert mocks vanuit interfaces;testifybiedt schonere assertionshttptest.ResponseRecorderlegt handler-output vast zonder network overhead- De
-race-vlag detecteert concurrency-bugs die unit tests anders missen - Coverage-metrics sturen de aandacht maar garanderen geen correctheid
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Zie jij de bug in Go?
Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Geschreven door
Anthony Fillion-MailletOprichter van SharpSkill
Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.
Bijgewerkt op 24 augustus 2026
Tags
Delen
Gerelateerde artikelen

Go Foutafhandeling in 2026: Patronen, Wrapping en Technische Interviewvragen
Uitgebreide gids over Go error handling: sentinel errors, error wrapping met fmt.Errorf, errors.Is/As en best practices voor technische interviews.

Go Design Patterns: Essentiële patronen en interviewvragen voor Go-ontwikkelaars
De zes belangrijkste Go design patterns met productieklare code: Functional Options, Strategy, Factory, Observer, Middleware en Struct Embedding. Inclusief veelgestelde interviewvragen.

Geavanceerde Go Interfaces in 2026: Compositie, Type Assertions en Sollicitatievragen
Een uitgebreide gids over Go interfaces: compositie via embedding, veilige type assertions, zelfreferentiële generics in Go 1.26 en de meest voorkomende sollicitatievragen voor senior ontwikkelaars.