Przejdź do głównej zawartości

Strategie danych testowych i fixtures

Twój zestaw testów używa 500-liniowego pliku seed skopiowanego z produkcji trzy lata temu. Połowa testów zależy od istnienia “John Doe” z emailem “john@test.com” i user ID 1. Gdy ktoś doda unique constraint na email, czterdzieści testów się psuje. Gdy schemat się zmienia, plik seed wymaga ręcznej aktualizacji zajmującej pół dnia. Dane testowe są fundamentem Twojej infrastruktury testowej — a większość zespołów traktuje je jako rzecz drugorzędną.

  • Implementację wzorca factory generującą spójne, realistyczne dane testowe na żądanie
  • Strategie zarządzania fixtures dla różnych warstw testowych (unit, integracyjne, E2E)
  • Generowanie danych zgodne z prywatnością naśladujące wzorce produkcyjne bez prawdziwych PII
  • Workflow seedowania bazy danych dla testów integracyjnych i E2E
  • Prompty do generowania fabryk danych testowych specyficznych dla domeny

Fabryki zastępują zahardkodowane dane testowe konfigurowalnymi generatorami produkującymi świeże, unikalne dane dla każdego testu.

@src/lib/db/schema.ts
Generate test data factories for every entity in our database schema:
For each table, create a factory at /tests/factories/{entity}.factory.ts that:
1. Uses @faker-js/faker for realistic data generation
2. Has build() - returns a plain object (for unit tests, no DB)
3. Has create(db) - inserts into the database and returns the record
4. Has buildList(count) - generates an array of objects
5. Has createList(db, count) - inserts multiple records
6. Supports overrides: build({ email: 'specific@test.com' })
7. Supports traits: build('admin'), build('suspended')
8. Handles foreign keys: OrderFactory.create() auto-creates a User if needed
9. Generates UNIQUE values (no collisions even with 1000 records)
Create a factory index at /tests/factories/index.ts that exports all factories.
Follow our Drizzle ORM patterns for database insertions.

Testy jednostkowe nigdy nie powinny dotykać bazy danych. Użyj build() do tworzenia czystych obiektów.

// Dobrze: czyste obiekty, bez bazy danych
const user = UserFactory.build({ role: 'admin' });
const result = authService.checkPermission(user, 'delete_users');
expect(result).toBe(true);

Testy integracyjne potrzebują rekordów w bazie danych, ale nie mogą wylewać stanu między testami.

Testy E2E potrzebują przewidywalnych danych utrzymujących się przez cały przebieg testu.

“Testy failują, bo fabryki generują dane naruszające reguły biznesowe.” Twoje fabryki potrzebują wiedzy domenowej. Dodaj walidację do fabryki: jeśli produkt jest “outOfStock”, stock musi być 0. Jeśli zamówienie jest “delivered”, musi mieć datę shipped_at przed delivered_at. Koduj reguły biznesowe w fabryce, nie tylko losowe dane.

“Tworzenie danych testowych jest wolne z powodu łańcuchów kluczy obcych.” Wstawiaj masowo zamiast tworzenia jednego rekordu na raz. Tworzenie współdzielonych danych referencyjnych (kategorie, role) raz w hooku beforeAll. Tworzenie danych specyficznych dla encji tylko per test.

“Plik seed ciągle rozjeżdża się ze zmianami schematu.” Generuj fabryki ze schematu, nie ręcznie. Gdy schemat się zmienia, przegeneruj: “Read the updated schema and update all factories to match. Add default values for new required columns.”

“Potrzebujemy danych produkcyjnych do debugowania, ale nie możemy ich użyć z powodu PII.” Użyj podejścia generowania zgodnego z prywatnością. Tworzenie syntetycznych danych odpowiadających rozkładom produkcyjnym. Do reprodukcji konkretnych bugów zanonimizuj rekord produkcyjny ręcznie: zamień email na faker email, imię na faker imię, ale zachowaj dane strukturalne reprodukujące buga.