Miejsce wykonywania testów

Zautomatyzowane testy można zazwyczaj uruchamiać ręcznie lub z pomocą platformy testowej, często nazywanej mechanizmem uruchamiającym testy, aby znaleźć i przeprowadzić testy. Możliwe jednak, że nie zawsze trzeba będzie uruchamiać skrypty ręcznie. Testy można przeprowadzać na wiele sposobów, dzięki którym można uzyskać informacje zwrotne i uzyskać pewność w różnych momentach cyklu programowania.

Skrypt warunku wstępnego

Projekty internetowe zwykle mają plik konfiguracji package.json konfigurowany przez npm, pnpm, Bun lub podobny. Ten plik konfiguracji zawiera zależności i inne informacje związane z projektem, a także skrypty pomocnicze. Mogą one dotyczyć kompilowania, uruchamiania lub testowania projektu.

W package.json dodaj skrypt o nazwie test, który opisuje, jak przeprowadzać testy. Jest to ważne, ponieważ gdy używasz npm lub podobnego narzędzia, skrypt „test” ma specjalne znaczenie. Ten skrypt może wskazywać pojedynczy plik, który zgłasza wyjątek (np. node tests.js), ale zalecamy, aby go używać, aby wskazać sprawdzone narzędzie do uruchamiania testów.

Jeśli do uruchamiania testu używasz Vitest, plik package.json będzie wyglądać tak:

{
  "name": "example-project",
  "scripts": {
    "start": "node server.js",
    "test": "vitest --run"
  }
}

Uruchomienie polecenia npm test z tym plikiem powoduje jednorazowe uruchomienie domyślnego zestawu testów Vitest. Ustawienie domyślne w Vitest to wyszukiwanie wszystkich plików z końcówką „.test.js” lub podobne i ich uruchomienie. Polecenie może się nieznacznie różnić w zależności od wybranego mechanizmu uruchamiania testów.

W trakcie tego kursu zdecydowaliśmy się wykorzystać na przykład Vitest, coraz bardziej popularne narzędzie do testowania. Więcej informacji o tej decyzji znajdziesz w Vitest jako użytkownik testowy. Pamiętaj jednak, że platformy i środowisko testowe – nawet w różnych językach – mają tendencję do łączenia się ze sobą.

Ręczne wywołanie testu

Ręczne aktywowanie testów automatycznych (np. użycie funkcji npm test w poprzednim przykładzie) może być przydatne podczas aktywnej pracy nad bazą kodu. Napisanie testów dla danej funkcji podczas jej opracowywania może pomóc Ci zorientować się, jak powinna ona działać. Dotyczy to koncepcji programowania opartego na testach (TDD).

Testerzy zwykle mają krótkie polecenie, które możesz wywołać, aby przeprowadzić niektóre lub wszystkie testy. Być może też jest to tryb obserwacji, w którym ponownie uruchamia się testy w miarę ich zapisywania. Wszystkie te opcje są przydatne podczas opracowywania nowej funkcji. Zostały zaprojektowane tak, aby ułatwić pisanie nowej funkcji, jej testów lub obu tych metod, a wszystko to w sposób szybki i przydatny. Na przykład Vitest działa domyślnie w trybie obserwacji: polecenie vitest wykrywa zmiany i ponownie uruchamia wszystkie znalezione testy. Zalecamy pozostawienie tego okna otwartego w innym oknie podczas pisania testów, ponieważ pozwoli Ci to szybko uzyskać informacje zwrotne na temat tworzonych testów.

Niektórzy biegacze umożliwiają też oznaczanie w kodzie testów jako only. Jeśli Twój kod zawiera testy only, będą one uruchamiane tylko w trakcie testowania, co przyspieszy tworzenie testów i ułatwi ich rozwiązywanie. Nawet wtedy, gdy wszystkie testy zakończą się szybko, użycie funkcji only może zmniejszyć nakład pracy i skrócić czas wykonywania testów niezwiązanych z funkcją lub testem, nad którym pracujesz.

W przypadku małych projektów, a zwłaszcza projektów, w których jest tylko jeden programista, możesz też wyrobić w sobie nawyk regularnego uruchamiania całego pakietu testowego bazy kodu. Jest to szczególnie przydatne, gdy testy są małe i zaczynają się szybko (w przypadku wszystkich testów nie powinno to potrwać dłużej niż kilka sekund), dzięki czemu sprawdzisz, czy wszystko działa, zanim przejdziesz dalej.

Przeprowadzanie testów w ramach wstępnego przesyłania lub sprawdzania

Podczas scalania kodu z powrotem z gałęzią main w wielu projektach sprawdza się, czy baza kodu działa prawidłowo. Jeśli dopiero zaczynasz testowanie, ale masz udział w projektach open source, zapewne udało Ci się zauważyć, że część procesu wysyłania żądań pull (PR) potwierdza, że wszystkie testy projektu zakończyły się powodzeniem, co oznacza, że Twoje nowe, ciekawe treści nie wpłynęły negatywnie na dotychczasowy projekt.

Jeśli przeprowadzasz testy lokalnie, repozytorium online projektu (np. GitHub lub inna usługa hostingu kodu) nie dowie się, że testy są pomyślne. Jeśli więc uruchomisz testy jako zadanie wstępnego przesyłania, wszyscy współtwórcy będą wiedzieć, że wszystko działa.

Na przykład GitHub określa je jako „sprawdzanie stanu”, które można dodać za pomocą działań GitHub. Działania GitHub to podstawowy rodzaj testu: aby działanie się zakończyło, każdy krok musi zakończyć się powodzeniem (nie może zakończyć się niepowodzeniem ani zgłosić Error). Możesz stosować działania do wszystkich PR w projekcie, a projekt może wymagać przejścia działań przed współtworzeniem kodu. Domyślne działanie środowiska Node.js na GitHubie uruchamia npm test.

Zrzut ekranu pokazujący proces testowy działań GitHub.
Zrzut ekranu pokazujący proces testowy w działaniach GitHub.

Takie podejście do testowania polega na zapewnieniu, że baza kodu jest zawsze „zielona” i nie akceptuje kodu, którego testy nie zostały wykonane.

Uruchamianie testów w ramach ciągłej integracji

Po zaakceptowaniu zielonego PR większość baz kodu ponownie uruchamia testy na podstawie gałęzi main projektu, a nie poprzedniego PR. Może się to zdarzyć natychmiast lub regularnie (np. co godzinę lub co noc). Te wyniki są często wyświetlane w panelu ciągłej integracji (CI), który pokazuje ogólny stan projektu.

Ten krok CI może wydawać się zbędny, zwłaszcza w przypadku projektów z małymi bazami kodu – testy zdane podczas weryfikacji powinny zakończyć się wraz z wprowadzeniem zmiany. Jednak nie zawsze tak jest. Testy mogą nagle zakończyć się niepowodzeniem, nawet po uzyskaniu zielonych wyników. Oto kilka przyczyn:

  • Kilka zmian zostało zaakceptowanych „jednocześnie”, co czasem określa się mianem warunku rasowego, i wpływają na siebie w subtelny, nietestowany sposób.
  • Testów nie da się odtworzyć lub testuje się w nich „niestabilny” kod – mogą zakończyć się powodzeniem i nieustannie bez wprowadzania zmian w kodzie.
    • Może się tak zdarzyć, jeśli korzystasz z systemów zewnętrznych w stosunku do bazy kodu. W przypadku serwera proxy wyobraź sobie, że testowanie funkcji Math.random() > 0.05 kończy się niepowodzeniem w 5% przypadków.
  • Niektóre testy są zbyt kosztowne lub kosztowne, jak na przykład testy kompleksowe (więcej na ten temat znajdziesz w typach testów automatycznych), a z czasem mogą przestać działać bez zasygnalizowania ich działania.

Żadnego z tych problemów nie da się przezwyciężyć, ale trzeba zdawać sobie sprawę, że testowanie i tworzenie oprogramowania w ogóle nie będą nauką ścisłą.

Przerwa na powrót do przeszłości

Gdy testy są przeprowadzane w ramach ciągłej integracji, a nawet w ramach kontroli stanu, może się zdarzyć, że kompilacja zakończy się kolorem czerwonym lub innym oznacza, że testy zakończą się niepowodzeniem. Jak już wspomnieliśmy, może się tak zdarzyć z różnych powodów, m.in. z powodu niepewności w przypadku wyścigu lub niepewnych wyników testów.

W przypadku mniejszych projektów Twoim instynktem może być potraktowanie ich jako kryzysu. Zatrzymaj wszystko, wycofaj je lub cofnij nieprawidłową zmianę i przywróć znany stan dobrego stanu. Takie podejście może być prawidłowe, ale pamiętaj, że testowanie (i ogólnie oprogramowanie) jest środkiem do osiągnięcia celu, a nie samym celem. Twoim celem jest prawdopodobnie napisanie oprogramowania, a nie zapewnienie zaliczenia wszystkich testów. Zamiast tego możesz wycofać zmiany do przodu, dodając do zmiany powodującej niezgodność inną, która naprawia błędy w testach.

Z drugiej strony zapewne zdarzyło Ci się pracować nad dużymi projektami, które funkcjonują w stanie wiecznie uszkodzone. Co gorsza, w dużym projekcie występują niepewne wyniki testów, które występują na tyle często, że powodują zmęczenie alarmem u programistów. Często jest to problem egzystencjalny, który muszą rozwiązać liderzy. Testy mogą być nawet wyłączane, ponieważ postrzegane są jako „przeszkadzające w rozwoju”.

Nie ma szybkiego rozwiązania tego problemu, ale pomaga ono zwiększyć wiarygodność testów (podnoszenie umiejętności) i zmniejszyć zakres testów (uproszczenie) i ułatwi wykrywanie błędów. Większa liczba testów komponentów lub testów integracji (więcej informacji o typach testów znajdziesz w artykule Rodzaje testów automatycznych) może dać więcej pewności niż jeden ogromny test kompleksowy, który jest trudny w obsłudze i robi wszystko za jednym razem.

Zasoby

Sprawdź swoją wiedzę

Jak nazywa się specjalny skrypt, którego npm i podobne programy szukają podczas testowania?

zaznacz
test
wstępnie przesłać
sprawdź