Przejdź do treści
juz-ide.pl blog
Wróć

Testy, które zawsze przechodzą

Paweł G.
3 min czytania
Testy, które zawsze przechodzą
Temat Technologia anti-overengineering

W bibliotece DDD, którą buduję, znalazłem we wrześniu coś nieprzyjemnego: testy wydajnościowe, które zawsze pokazywały 70% poprawy.

Zawsze. Niezależnie od tego, co zmieniłem w kodzie.

Jak to wygląda, kiedy jest w kodzie

Wyobraź sobie test, który sprawdza, czy Twój system cache’owania działa wydajnie. Test uruchamiasz, widzisz wynik: „poprawa: 73%”. Commitujesz, idziesz dalej.

Problem: ten wynik nie pochodzi z mierzenia. Pochodzi z liczby, którą ktoś (ja) wpisał na stałe, żeby test „przechodził”.

We wrześniu przejrzałem testy wydajnościowe biblioteki i zobaczyłem kilka takich miejsc:

  • Współczynnik trafień cache’a wpisany ręcznie zamiast zmierzony
  • „Poprawa” liczona jako losowa liczba z określonego zakresu
  • Benchmarki porównujące nie dwa działające algorytmy, tylko dwie stałe

Testy te nigdy nie mogły stwierdzić, że coś jest wolniejsze. Bo nie mierzyły niczego.

Skąd to się bierze

Kiedy piszesz sam, bez code review, łatwo wpaść w pętlę: chcesz mieć zielone testy → piszesz testy, które są zielone → idziesz dalej.

Nie z nieuczciwości. Z pośpiechu i z tego, że trudno jest zmierzyć wydajność naprawdę — trzeba izolować środowisko, wyeliminować szum, porównywać warunki. To żmudne. Łatwiej napisać coś, co „wygląda jak benchmark”.

Najtrudniejsze w tym odkryciu było to, jak przekonująco te liczby wyglądały. Fałszywe benchmarki żyły w repo tylko kilka dni — ale przez te kilka dni miałem zupełnie realne poczucie, że wydajność biblioteki jest zmierzona i potwierdzona. Nie była.

Co to mówi o pisaniu z AI

Część tego kodu powstała z pomocą asystentów AI. AI pisze pewnie, wygląda przekonująco, i może napisać test wydajnościowy z hardkodowaną wartością tak samo sprawnie jak z prawdziwym pomiarem. Różnica nie jest widoczna na pierwszy rzut oka — widoczna jest dopiero, gdy zaczniesz analizować, co test właściwie sprawdza.

Kod napisany z AI wymaga takiej samej — albo większej — czujności jak kod pisany przez kogoś innego. Może wyglądać poprawnie i być zupełnie pusty w środku.

Jak wygląda prawdziwy benchmark w tej bibliotece

Prawdziwy benchmark izoluje mierzony fragment: uruchamia go w pętli (wystarczy kilkanaście tysięcy iteracji), odrzuca pierwsze wykonania (rozgrzewka JIT), mierzy medianę i percentyle (p95, p99), nie średnią.

Porównanie „z/bez cache” wymaga identycznych warunków: ten sam rozmiar danych, ta sama kolejność operacji, wymuszony GC przed startem.

Wartość cacheHitRate = 0.95 nigdy nie powinna pojawiać się w teście — tylko jako wynik pomiaru, nie jako założenie.



Poprzedni wpis
Wrzesień 2025: miesiąc, w którym kasowałem kod
Następny wpis
Aplikacja mobilna zaczyna istnieć