Przejdź do głównej zawartości

Wzorce testowania integracyjnego

Twoje testy jednostkowe mockują bazę danych i przechodzą z wyróżnieniem. Potem wdrażasz i odkrywasz, że migracja Drizzle ORM zmieniła typ kolumny z varchar(255) na text, co spowodowało, że Twój unique constraint po cichu przestał działać. Mock nigdy o tym nie wiedział. Testy integracyjne istnieją, żeby łapać rzeczy, które się zdarzają, gdy prawdziwe komponenty ze sobą rozmawiają — dokładnie tam, gdzie bugi się ukrywają.

  • Wzorce testów integracyjnych z bazą danych z właściwym setup, teardown i izolacją
  • Workflow testowania kontraktów API łapiących breaking changes między serwisami
  • Strategie testowania kolejek wiadomości, cache’ów i integracji z zewnętrznymi serwisami
  • Prompty AI generujące kompletną infrastrukturę testową, nie tylko przypadki testowe
  • Techniki utrzymywania testów integracyjnych na tyle szybkich, by działały w CI

Testy integracyjne potrzebują prawdziwej bazy danych, ale nie Twojej produkcyjnej. Skonfiguruj izolowaną testową bazę danych, która resetuje się między testami.

@src/lib/db/schema.ts @tests/setup.ts
Create a database integration test setup for our Drizzle ORM + PostgreSQL project:
1. A setup file that:
- Creates a test database (or uses a container via testcontainers)
- Runs all migrations before the test suite
- Provides a clean transaction wrapper per test (rollback after each)
- Exports a `getTestDb()` helper that returns an isolated database connection
2. An example test for UserRepository.create that:
- Uses the real database (not mocks)
- Verifies the record exists after creation
- Checks unique constraint enforcement (duplicate email)
- Verifies cascade deletes work correctly
- Tests NULL handling for optional fields
Follow our existing test patterns in @tests/setup.ts

Gdy Twój serwis konsumuje API innego serwisu, testy kontraktowe weryfikują integrację bez uruchamiania obu serwisów.

Testowanie integracji opartych na zdarzeniach wymaga weryfikacji publikacji, konsumpcji i kolejności wiadomości.

Dla zewnętrznych API, nad którymi nie masz kontroli (Stripe, Twilio, SendGrid), użyj stub serwerów symulujących zachowanie API.

Create a stub server for the Stripe API that we can use in integration tests.
The stub should handle:
1. POST /v1/charges - Return success with a charge ID
2. POST /v1/charges - Return 402 when amount > 999999 (simulates declined)
3. POST /v1/refunds - Return success with refund ID
4. GET /v1/charges/{id} - Return charge details for known IDs, 404 for unknown
Implementation:
- Use Express with a random port (for parallel test execution)
- Store created charges in memory (so GET returns what POST created)
- Include a reset() method to clear state between tests
- Export a factory: createStripeStub() returns { url, server, reset }
Save to /tests/stubs/stripe.stub.ts
  1. Równoległij z izolacją

    Uruchamiaj niezależne zestawy testów równolegle. Każdy zestaw dostaje własny schemat bazy danych lub kontener.

  2. Współdzielone kontenery testowe

    Uruchom kontener bazy danych raz dla całego zestawu, nie na plik testowy. Użyj rollback transakcji do izolacji per-test.

  3. Selektywne uruchamianie

    Taguj testy i uruchamiaj tylko dotknięte testy integracyjne: npm test -- --testPathPattern=integration/order gdy pracujesz nad kodem zamówień.

  4. Seedowanie vs. setup per-test

    Dla testów read-only seeduj dane referencyjne raz. Tworzenie danych per-test tylko dla testów, które je modyfikują.

  5. Cache’owanie kontenerów w CI

    Cache’uj obrazy Docker w pipeline CI, aby unikać ściągania ich przy każdym uruchomieniu.

“Testy integracyjne są niestabilne i losowo failują w CI.” Główne przyczyny: współdzielony stan bazy danych między testami, zahardkodowane porty kolidujące w równoległych uruchomieniach i asercje zależne od timingu. Użyj rollback transakcji do izolacji, losowych portów dla serwisów i pętli pollingu zamiast setTimeout dla operacji asynchronicznych.

“Testy przechodzą lokalnie, ale failują w CI.” Sprawdź różnice w wersjach bazy danych, brakujące zmienne środowiskowe i sieć Docker. Użyj testcontainers, aby zapewnić tę samą wersję bazy danych wszędzie. Przypnij obrazy kontenerów do konkretnych wersji.

“Testy integracyjne są zbyt wolne, by uruchamiać je na każdym commit.” Uruchamiaj tylko dotknięte testy integracyjne na commitach (na podstawie zmienionych plików). Uruchamiaj pełny zestaw przy merge do PR i w nocy. To daje szybki feedback podczas developmentu i kompleksową weryfikację przed merge.

“AI wygenerowało testy zależne od kolejności wstawiania.” Wyniki zapytań bazodanowych są nieuporządkowane, chyba że określisz ORDER BY. Poproś AI “sort results before asserting, or assert on set membership rather than array equality.”