# 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. - Published: 2026-08-24 - Updated: 2026-08-24 - Author: Anthony Fillion-Maillet - Tags: go, testing, unit-tests, mocking, interview - Reading time: 9 min --- 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. > **Waar interviewers op letten** > > 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. ```go // calculator_test.go 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](https://cs.opensource.google/go/go/+/refs/tags/go1.23.1:src/strings/strings_test.go) en in productiecodebases in de hele industrie. ```go // validator_test.go 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. ```go // service.go 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](https://github.com/uber-go/mock)-pakket genereert mock-implementaties vanuit interface-definities. Het `mockgen`-commando leest bronbestanden en produceert mock-structs die aanroepen registreren en geconfigureerde waarden retourneren. ```bash # Genereer mocks voor de Repository interface mockgen -source=service.go -destination=mocks/repository_mock.go -package=mocks ``` Gebruik van de gegenereerde mock in tests: ```go // service_test.go 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](https://github.com/stretchr/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. ```go // user_test.go 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. ## 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. ```go // handler_test.go 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](/technologies/go/interview-questions/testing) 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. ```bash # 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](/blog/go/go-concurrency-goroutines-channels) 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 - `gomock` genereert mocks vanuit interfaces; `testify` biedt schonere assertions - `httptest.ResponseRecorder` legt 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 --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/nl/blog/go/go-testing-2026-unit-tests-mocks-interview