# Testowanie w Go w 2026: Testy jednostkowe, mocki i pytania rekrutacyjne > Opanuj testowanie w Go z biblioteką standardową, testami tabelarycznymi, mockami i wzorcami oczekiwanymi na rozmowach kwalifikacyjnych. Praktyczne przykłady z testify, gomock i pakietem testing. - Published: 2026-08-24 - Updated: 2026-08-24 - Author: Anthony Fillion-Maillet - Tags: go, testing, unit-tests, mocks, interview - Reading time: 9 min --- Testowanie w Go opiera się na standardowym pakiecie `testing`, który jest dostarczany z każdą instalacją Go i nie wymaga żadnych zewnętrznych zależności. W przeciwieństwie do frameworków w innych językach, podejście Go preferuje prostotę: pliki testowe znajdują się obok kodu produkcyjnego, funkcje testowe przestrzegają konwencji nazewnictwa, a polecenie `go test` obsługuje wykrywanie i wykonywanie testów. > **Czego szukają rekruterzy** > > Kandydatów, którzy piszą testy tabelaryczne, używają interfejsów do wstrzykiwania zależności i rozumieją, kiedy mockowanie wnosi wartość, a kiedy tylko niepotrzebną złożoność. ## Pisanie testów jednostkowych z pakietem testing Każdy plik testowy kończy się na `_test.go` i znajduje się w tym samym pakiecie co testowany kod. Funkcje testowe zaczynają się od `Test` i nazwy pisanej wielką literą. Parametr `*testing.T` dostarcza metod do raportowania błędów. ```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) } } ``` Uruchomienie `go test ./...` wykonuje wszystkie testy w bieżącym module. Flaga `-v` pokazuje nazwy poszczególnych testów i ich status pass/fail. ## Testy tabelaryczne: standard w Go Testy tabelaryczne redukują duplikację i czynią dodawanie nowych przypadków trywialnym. Każdy wiersz w tabeli reprezentuje jeden scenariusz z danymi wejściowymi i oczekiwanymi wynikami. Ten wzorzec występuje w [bibliotece standardowej Go](https://cs.opensource.google/go/go/+/refs/tags/go1.23.1:src/strings/strings_test.go) oraz w produkcyjnych bazach kodu w całej branży. ```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) } }) } } ``` Metoda `t.Run` tworzy podtesty, które działają niezależnie. Nieudane podtesty raportują, który konkretny przypadek zawiódł, nie zatrzymując pozostałych przypadków. ## Wstrzykiwanie zależności przez interfejsy Interfejsy Go umożliwiają testowanie kodu zależnego od systemów zewnętrznych: baz danych, klientów HTTP, systemów plików. Definiowanie minimalnego interfejsu w miejscu użycia pozwala na zamianę prawdziwych implementacji na testowe dublerów. ```go // service.go package order // Repository defines the data access methods this service needs type Repository interface { FindByID(id string) (*Order, error) Save(order *Order) error } // Service handles order business logic type Service struct { repo Repository } // NewService creates a service with the given repository func NewService(repo Repository) *Service { return &Service{repo: repo} } // Process validates and saves an order func (s *Service) Process(order *Order) error { if order.Total <= 0 { return ErrInvalidTotal } return s.repo.Save(order) } ``` `Service` akceptuje dowolny typ spełniający interfejs `Repository`. Kod produkcyjny przekazuje implementację opartą na bazie danych. Testy przekazują mock lub stub. ## Mockowanie z gomock i mockgen Pakiet [gomock](https://github.com/uber-go/mock) generuje implementacje mocków z definicji interfejsów. Polecenie `mockgen` odczytuje pliki źródłowe i produkuje struktury mocków, które rejestrują wywołania i zwracają skonfigurowane wartości. ```bash # Generate mocks for the Repository interface mockgen -source=service.go -destination=mocks/repository_mock.go -package=mocks ``` Użycie wygenerowanego mocka w testach: ```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} // Expect Save to be called once with this order, return 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) // No calls expected to repo since validation fails first svc := NewService(mockRepo) err := svc.Process(&Order{ID: "456", Total: 0}) assert.ErrorIs(t, err, ErrInvalidTotal) } ``` Mock weryfikuje, że `Save` została wywołana dokładnie raz z oczekiwanym argumentem. Jeśli testowany kod nigdy nie wywoła `Save` lub wywoła ją z innymi argumentami, test nie przejdzie. ## Używanie testify do asercji i zestawów testów [testify](https://github.com/stretchr/testify) dostarcza funkcje asercji, które produkują czytelniejsze komunikaty o błędach niż ręczne sprawdzenia if. Pakiet `assert` kontynuuje wykonywanie po błędach. Pakiet `require` zatrzymuje test natychmiast. ```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") } ``` Wywołanie `require.NoError` zatrzymuje test, jeśli parsowanie nie powiedzie się, zapobiegając panikom typu nil pointer w kolejnych asercjach. ## Testowanie handlerów HTTP z httptest Pakiet `net/http/httptest` dostarcza `ResponseRecorder` do przechwytywania wyjścia handlera oraz `Server` do uruchamiania lokalnego serwera testowego. Większość testów jednostkowych używa `ResponseRecorder`, aby uniknąć narzutu sieciowego. ```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()) } ``` Dla handlerów wywołujących zewnętrzne serwisy należy wstrzyknąć mock klienta lub użyć `httptest.NewServer` do utworzenia fałszywego backendu. ## Typowe pytania rekrutacyjne dotyczące testowania w Go Rekruterzy oceniają wiedzę o testowaniu poprzez pytania, które ujawniają doświadczenie z prawdziwymi bazami kodu. Oto wzorce wyróżniające przygotowanych kandydatów: **"Jak przetestowałbyś funkcję wywołującą zewnętrzne API?"** Zdefiniuj interfejs dla klienta HTTP, wstrzyknij go do funkcji lub struktury i dostarcz mock zwracający ustalone odpowiedzi. To eliminuje wywołania sieciowe i czyni testy deterministycznymi. **"Kiedy użyłbyś stuba zamiast mocka?"** Study zwracają ustalone odpowiedzi bez weryfikowania sposobu ich wywołania. Mocki weryfikują, że określone metody zostały wywołane z określonymi argumentami. Używaj stubów, gdy wartość zwracana jest ważniejsza niż interakcja. Używaj mocków, gdy weryfikacja interakcji jest celem testu. **"Czym są testy tabelaryczne i dlaczego Go je preferuje?"** Testy tabelaryczne definiują przypadki testowe jako dane w slice struktur. Redukują boilerplate, czynią dodawanie przypadków trywialnym i produkują czytelne wyjście testowe z `t.Run`. Wzorzec jest zgodny z preferencją Go dla jawnego, powtarzalnego kodu zamiast sprytnych abstrakcji. **"Jak obsługujesz fixtures testowe lub setup współdzielony przez wiele testów?"** Użyj `TestMain` do setupu i teardownu na poziomie pakietu. Używaj funkcji pomocniczych lub zestawów testów (z testify) do współdzielonego setupu między powiązanymi testami. Unikaj globalnego stanu, który tworzy sprzężenie między testami. Przygotowujesz się do rozmowy rekrutacyjnej o Go? [Moduł testowania Go](/technologies/go/interview-questions/testing) szczegółowo omawia te wzorce wraz z pytaniami praktycznymi. ## Uruchamianie testów z pokryciem i wykrywaniem wyścigów Polecenie `go test` akceptuje flagi ujawniające nietestowane ścieżki kodu i błędy współbieżności. ```bash # Run tests with coverage report go test -cover ./... # Generate HTML coverage visualization go test -coverprofile=coverage.out ./... go tool cover -html=coverage.out -o coverage.html # Detect race conditions (slower, but catches real bugs) go test -race ./... ``` Detektor wyścigów instrumentuje dostępy do pamięci i oznacza równoczesne odczyty i zapisy do tej samej zmiennej. Uruchamianie testów z `-race` w CI wyłapuje błędy, które manifestują się tylko przy określonym timingu. ## Organizacja testów w dużych bazach kodu W miarę wzrostu projektów organizacja testów wpływa na utrzymywalność: - **Testy w tym samym pakiecie** (`package foo`) mają dostęp do nieeksportowanych funkcji i pól. Używaj do testów jednostkowych weryfikujących wewnętrzne zachowanie. - **Testy w zewnętrznym pakiecie** (`package foo_test`) importują pakiet jak kod zewnętrzny. Używaj do testów integracyjnych i do weryfikacji publicznego API. - **Katalogi testdata** przechowują fixtures takie jak pliki JSON, golden outputs lub seed databases. Go ignoruje je podczas budowania. - **Build tags** oddzielają testy jednostkowe od testów integracyjnych wymagających systemów zewnętrznych. Uruchom `go test -tags=integration ./...`, aby je uwzględnić. Więcej o dobrych praktykach Go poza testowaniem znajdziesz w [artykule o wzorcach współbieżności](/blog/go/go-concurrency-goroutines-channels), który omawia gorutyny i kanały. ## Co zapamiętać o testowaniu w Go - Pakiet `testing` jest dostarczany z Go i nie wymaga zewnętrznych zależności - Testy tabelaryczne redukują duplikację i są oczekiwanym wzorcem na rozmowach rekrutacyjnych - Interfejsy umożliwiają wstrzykiwanie zależności; definiuj je w miejscu użycia, nie w implementacji - `gomock` generuje mocki z interfejsów; `testify` dostarcza czytelniejsze asercje - `httptest.ResponseRecorder` przechwytuje wyjście handlera bez narzutu sieciowego - Flaga `-race` wykrywa błędy współbieżności, które testy jednostkowe inaczej pomijają - Metryki pokrycia kierują uwagą, ale nie gwarantują poprawności --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/go/go-testing-2026-unit-tests-mocks-interview