Dane testowe i fixture'y

Po utworzeniu projektu za pomocą:

goat init ./my-project \
  --name my-project \
  --git-repo git@github.com:your-user/my-project.git \
  --terminal-prefix MYAPP \
  --default-language en \
  --supported-languages en,pl \
  --template goatcms

otrzymujesz nie tylko strukturę aplikacji, ale również przykładowe dane i dokumenty dopasowane do aktualnej wersji Goat.

Dzięki temu możesz od razu uruchomić projekt i zobaczyć działającą aplikację z przykładową zawartością, bez konieczności ręcznego przygotowywania danych startowych.

Fixture'y pełnią więc dwie role:

  • dostarczają dane potrzebne do lokalnego developmentu i testów,
  • tworzą przykładową dokumentację zgodną z wersją generatora, której aktualnie używasz.

To szczególnie przydatne przy aktualizacji projektu. Dokumentacja i przykłady mogą być wersjonowane razem z kodem, dzięki czemu łatwiej sprawdzić, jak działa konkretna wersja aplikacji.

Główny fixture projektu

Logika odpowiedzialna za ładowanie danych znajduje się w:

herd/fixture.goat

Skrypt może tworzyć lub aktualizować między innymi:

  • dokumenty,
  • dane przykładowe,
  • rekordy wymagane przez aplikację,
  • treści demonstracyjne,
  • dane potrzebne podczas lokalnego developmentu.

herd/fixture.goat jest wykonywany podczas uruchamiania środowiska developerskiego przez:

herd/dev.goat

Dzięki temu po uruchomieniu projektu lokalna aplikacja może automatycznie otrzymać zestaw danych potrzebnych do pracy.

Fixture można również uruchomić ręcznie.

Dokumentacja jako dane aplikacji

Przykładowa dokumentacja jest przechowywana w plikach Markdown.

Domyślna struktura wygląda następująco:

herd/fixtures/doc/<ver>/<lang>/<slug>.md

gdzie:

  • <ver> określa wersję dokumentacji,
  • <lang> określa język,
  • <slug> jest stabilnym identyfikatorem dokumentu.

Przykład:

herd/fixtures/doc/v1/pl/architektura.md

Takie podejście pozwala przechowywać dokumentację jako zwykłe pliki tekstowe razem z projektem.

Możesz je:

  • wersjonować w Git,
  • przeglądać w code review,
  • edytować w dowolnym edytorze,
  • modyfikować przy pomocy AI,
  • tłumaczyć,
  • ładować ponownie do aplikacji.

Dokumentacja pozostaje więc częścią kodu źródłowego projektu, a nie treścią istniejącą wyłącznie w bazie danych.

Ładowanie dokumentów Markdown

Pliki Markdown są ładowane przez:

herd/fixture.goat

z wykorzystaniem komendy:

crud:doc:persist

Przykład:

crud:doc:persist \
  --lang=pl \
  --slug="moj-dokument" \
  --title="Mój dokument" \
  --description="Krótki opis dla wyszukiwarek i udostępnień." \
  --body-markdown-file="herd/fixtures/doc/v1/pl/moj-dokument.md"

Treść dokumentu jest pobierana bezpośrednio z pliku wskazanego przez:

--body-markdown-file

Metadane, takie jak tytuł, język, slug czy opis, są przekazywane osobno.

Pozwala to oddzielić właściwą treść Markdown od informacji wykorzystywanych przez aplikację, SEO lub mechanizmy wyszukiwania.

persist zamiast tworzenia duplikatów

Komenda:

crud:doc:persist

jest przeznaczona do wielokrotnego uruchamiania.

Zamiast za każdym razem tworzyć nowy rekord, wyszukuje istniejący dokument po jego identyfikatorze i aktualizuje go, jeżeli już istnieje.

Dzięki temu fixture'y mogą być idempotentne — wielokrotne uruchomienie tego samego skryptu powinno prowadzić do tego samego oczekiwanego stanu danych zamiast tworzenia kolejnych kopii tych samych rekordów.

Dla encji dziedziczących po content identyfikacja dokumentu opiera się na parze:

lang + slug

Przykładowo:

pl + architektura
en + architecture

są traktowane jako dwa różne dokumenty.

Podczas aktualizacji istniejącej treści zachowuj więc spójne wartości lang i slug.

Zmiana sluga może spowodować utworzenie nowego rekordu zamiast aktualizacji dotychczasowego.

Stabilne slugi

Slug warto traktować jako techniczny identyfikator dokumentu, a nie tylko uproszczoną wersję tytułu.

Dobry slug powinien być:

  • krótki,
  • stabilny,
  • zapisany małymi literami,
  • pozbawiony znaków specjalnych,
  • rozdzielany myślnikami.

Przykłady:

architektura
baza-danych
testowanie
model-i-generowanie

Nie zmieniaj sluga tylko dlatego, że zmienił się tytuł dokumentu.

Przykładowo dokument:

slug: architektura

może mieć później tytuł:

Architektura aplikacji Goat

bez konieczności zmiany jego identyfikatora.

Pomaga to zachować stabilne adresy URL i poprawnie aktualizować rekordy przez persist.

Wersjonowanie dokumentacji

Katalog:

herd/fixtures/doc/<ver>/

pozwala przechowywać dokumentację przypisaną do konkretnej wersji projektu lub generatora.

Może to być przydatne, gdy kolejne wersje Goat zmieniają:

  • strukturę projektu,
  • składnię modelu,
  • dostępne komendy,
  • zachowanie generatora,
  • sposób konfiguracji aplikacji.

Dzięki temu użytkownik może pracować z dokumentacją odpowiadającą wersji kodu, którą rzeczywiście ma przed sobą.

To bezpieczniejsze niż poleganie wyłącznie na zewnętrznej dokumentacji, która może opisywać nowszą lub starszą wersję narzędzia.

Ręczne uruchomienie fixture'ów

Po zbudowaniu aplikacji fixture można załadować ręcznie za pomocą CLI wygenerowanej aplikacji:

myapp run:script --path=herd/fixture.goat

Jest to przydatne, gdy:

  • zmieniłeś dokumentację,
  • dodałeś nowe dane przykładowe,
  • chcesz odświeżyć lokalny stan aplikacji,
  • testujesz działanie fixture'u,
  • nie chcesz ponownie uruchamiać całego środowiska developerskiego.

Ponieważ dane są ładowane za pomocą operacji typu persist, ponowne uruchomienie fixture'u powinno przede wszystkim aktualizować istniejące rekordy zamiast tworzyć ich duplikaty.

Fixture'y w codziennej pracy

Typowy workflow podczas edycji dokumentacji może wyglądać tak:

zmiana pliku Markdown
        ↓
uruchomienie herd/fixture.goat
        ↓
aktualizacja dokumentu w bazie
        ↓
sprawdzenie rezultatu w aplikacji

Przykładowo:

vim herd/fixtures/doc/v1/pl/architektura.md

myapp run:script --path=herd/fixture.goat

Nie musisz ręcznie kopiować treści do bazy ani edytować rekordów przez panel administracyjny.

Fixture'y a testy

Fixture'y powinny tworzyć przewidywalny stan początkowy.

Dobre dane testowe są:

  • deterministyczne,
  • możliwe do wielokrotnego załadowania,
  • niezależne od danych produkcyjnych,
  • niewrażliwe na kolejność ręcznych operacji,
  • wystarczająco kompletne, aby uruchomić podstawowe scenariusze aplikacji.

W miarę możliwości unikaj generowania przypadkowych danych, jeżeli konkretne wartości są później używane przez testy.

Stabilne dane ułatwiają:

  • testy E2E,
  • debugowanie,
  • odtwarzanie błędów,
  • przygotowanie środowiska dla nowego programisty,
  • porównywanie zachowania kolejnych wersji aplikacji.

Dane przykładowe a dane produkcyjne

Fixture'y są przeznaczone przede wszystkim dla środowisk developerskich, testowych i demonstracyjnych.

Nie umieszczaj w nich:

  • prawdziwych danych użytkowników,
  • haseł,
  • tokenów,
  • kluczy API,
  • sekretów,
  • kopii danych produkcyjnych zawierających informacje poufne.

Dane przechowywane w herd/fixtures/ należy traktować jako część repozytorium i zakładać, że mogą być dostępne dla każdego, kto ma dostęp do kodu projektu.

Wskazówki redakcyjne dla dokumentacji

Każdy plik Markdown powinien zawierać treść w jednym języku.

Język dokumentu określaj przez strukturę katalogów oraz parametr:

--lang

Zachowuj stabilne slugi i nie uzależniaj ich od drobnych zmian tytułu.

Tytuł i opis zapisuj w fixture'ze:

--title="Mój dokument"
--description="Krótki opis dokumentu."

Dzięki temu metadane są przechowywane razem z definicją danych i mogą być wykorzystane między innymi przez:

  • SEO,
  • wyszukiwarkę,
  • listy dokumentów,
  • udostępnianie treści,
  • przyszłe wersje językowe.

Treść właściwą przechowuj natomiast w osobnym pliku Markdown.

Dokumentacja dostępna od pierwszego uruchomienia

Jedną z zalet fixture'ów dostarczanych przez goat init jest możliwość uruchomienia projektu razem z dokumentacją odpowiadającą jego wersji.

Workflow wygląda w uproszczeniu tak:

goat init
    ↓
wygenerowanie projektu
    ↓
uruchomienie środowiska
    ↓
załadowanie fixture'ów
    ↓
gotowa aplikacja z dokumentacją i przykładowymi danymi

Dzięki temu nowy projekt nie zaczyna się od pustej aplikacji.

Od pierwszego uruchomienia możesz zobaczyć działające przykłady, strukturę danych oraz dokumentację przygotowaną dla używanej wersji Goat.

To sprawia, że fixture'y są nie tylko mechanizmem ładowania danych testowych, ale również elementem samodokumentującego się projektu.