← Back to Blog

Testy jednostkowe jako zabezpieczenie przed niezamierzonymi zmianami

Testy jednostkowe jako zabezpieczenie przed niezamierzonymi zmianami

Oczekujemy, że testy jednostkowe zweryfikują poprawność zmodyfikowanej logiki i pomogą wychwycić niezamierzone zmiany w zachowaniu aplikacji. Przy programowaniu z AI niezbędne jest też sprawdzenie, czy funkcjonalność spoza zakresu zadania pozostała nienaruszona.

Weryfikacja, że nowa funkcja działa, to więc tylko część pracy. Musimy też sprawdzić, czy zmiana nie zepsuła istniejących reguł aplikacji.

Co powinny chronić testy jednostkowe

Testy jednostkowe weryfikują zachowanie poszczególnych części kodu. Działają też jako zabezpieczenie przed regresjami, czyli błędami wprowadzonymi przez zmianę zachowania, które wcześniej działało.

Ta ochrona jest szczególnie cenna w przypadku kodu generowanego przez AI. AI może spełnić konkretne wymaganie, jednocześnie zmieniając logikę, która miała pozostać nietknięta.

Dobrze zaprojektowane testy pomagają wyznaczyć granice zmiany:

To jest zachowanie, które chcemy zmienić. Te reguły muszą nadal obowiązywać.

Testuj według ryzyka i rzeczywistych zależności

Nie musimy automatycznie pisać osobnego testu dla każdego gettera, settera czy prostej klasy danych.

Test, który jedynie powtarza implementację, może zwiększyć liczbę testów, nie dodając wiele wartości. Tworzy też więcej pracy utrzymaniowej przy kolejnych zmianach.

Praktyczna zasada brzmi:

Przy konkretnej zmianie skup się na zmodyfikowanym zachowaniu i częściach aplikacji, które od niego zależą. Zakres testowania ustal na podstawie potencjalnego wpływu.

W przypadku prostych metod bez logiki decyzyjnej osobny test jednostkowy może być zbędny, jeśli inne testy odpowiednio pokrywają ich zachowanie.

Sama prostota nie jest jednak powodem, by zakładać, że AI się nie pomyli. Nawet jednowierszowa metoda może decydować o cenie zamówienia lub o prawach dostępu użytkownika.

Zanim dodasz test, zadaj trzy pytania:

  1. Jakie zachowanie zmienia się w tym zadaniu?

Weryfikujemy, czy zmiana spełnia wymagania.

  1. Które reguły i zależne komponenty muszą pozostać nienaruszone?

Szukamy miejsc, w których zmiana mogłaby spowodować regresję.

  1. Czy test wychwyci prawdziwy błąd?

Weryfikujemy oczekiwane zachowanie, a nie tylko kopiujemy implementację.

Testy muszą łączyć się z logiką biznesową

Najcenniejsze testy jednostkowe chronią konkretne reguły aplikacji.

W przypadku metody obliczającej rabat na przykład nie wystarczy sprawdzić, że zwraca liczbę. Musimy wiedzieć, czy nadal obowiązują te reguły:

  • rabat nie przekracza dozwolonego limitu;

  • cena końcowa nie spada poniżej zera;

  • klient, któremu rabat nie przysługuje, płaci pełną cenę;

  • obliczenie przestrzega zdefiniowanych reguł zaokrąglania.

Powiązanie między metodą a regułą biznesową nadaje testowi sens.

Implementacja może się zmienić. Reguła spoza zamierzonego zakresu zadania musi pozostać nienaruszona.

Jak podchodzi do tego AITM

AITM łączy rozwój z AI z kontekstem projektu, kontraktami i zależnościami między różnymi częściami aplikacji.

Przed implementacją architekt określa, co powinno się zmienić, jak powiązane są odpowiednie części i które reguły muszą pozostać nienaruszone. Krok testowania wykorzystuje następnie te informacje.

Kluczowe pytanie to więc nie tylko to, czy AI potrafi napisać test. Chodzi o to, czy AI wie, co test ma chronić i dlaczego.

Weźmy zmianę w DiscountService.calculateDiscount(). Jeśli kontrakt używa dependsOnModules, aby zapisać, że OrderSummary.render() również zależy od obliczania rabatu, krok testowania ma powód, by sprawdzić także wpływ na podsumowanie zamówienia.

Samo obliczenie można sprawdzić testem jednostkowym. Do sprawdzenia, jak obliczenie współpracuje z podsumowaniem zamówienia, bardziej odpowiedni może być test integracyjny.

Testy są więc projektowane wokół rzeczywistych zależności i ryzyk konkretnej zmiany.

Dziesięć testów dla jednego zadania, dwa tysiące dla innego

Nie każde zadanie wymaga takiego samego zakresu testowania.

Dla ilustracji: w projekcie z 32 467 testami mała zmiana może wymagać uruchomienia dziesięciu odpowiednich testów. Zmiana we wspólnej logice biznesowej może wymagać dwóch tysięcy.

Celem testowania celowanego jest wybranie testów, które pokrywają zmodyfikowane zachowanie i jego zależności. Może to skrócić cykl informacji zwrotnej i skupić weryfikację na ryzykach danego zadania.

Szersze kontrole regresji lub pełny zestaw testów nadal mają swoje miejsce przy rozległych zmianach lub przed nowym wydaniem.

Liczba uruchamianych testów powinna odpowiadać wpływowi zmiany.

Gdy test nie przechodzi, musimy zrozumieć dlaczego

Niezaliczony test nie zawsze oznacza ten sam problem. Musimy rozróżnić te sytuacje:

  • w implementacji wprowadzono błąd;

  • zmiana nieumyślnie naruszyła istniejącą regułę biznesową;

  • nowa funkcja celowo zmieniła oczekiwane zachowanie i test wymaga aktualizacji.

Wymagania zadania, kontrakty i opisy logiki biznesowej dostarczają kontekstu do tej oceny.

Jeśli wymaganie zmieniło się zasadnie, odpowiedni test też musi się zmienić. Jeśli AI naruszyło regułę, która miała pozostać nienaruszona, trzeba poprawić implementację.

Samo zmodyfikowanie testu tak, by znów przechodził, może ukryć prawdziwy błąd.

Testy jednostkowe to pierwsza warstwa ochrony

Każdy poziom testowania pełni inną rolę:

  • Testy jednostkowe weryfikują poszczególne części logiki.

  • Testy integracyjne weryfikują, jak moduły i systemy współpracują.

  • Testy E2E sprawdzają kompletne ścieżki użytkownika w działającej aplikacji.

Te warstwy się uzupełniają. Każda wychwytuje inne rodzaje błędów i pomaga zweryfikować zmianę z innej perspektywy.

Przy programowaniu z AI sprawdzamy więc dwie rzeczy: czy zadanie zostało wykonane i czy zachowanie spoza zamierzonego zakresu pozostało nienaruszone.

Łączenie wymagań zadania, logiki biznesowej, zależności i testów jest ważną częścią orkiestracji AITM.

Unit Tests as a safeguard against unintended changes — screenshot 1

Np. testy jednostkowe

Dowiedz się więcej na https://www.aitm.cz

#AITM #UnitTesting #SoftwareTesting #AI #SoftwareDevelopment