Mariusz Tober

Generator testów z dokumentacji: najważniejsze jest pokrycie, nie prompt

4 min czytania#testy#llm#lokalne modele

Chciałem zbudować narzędzie, które bierze dokumentację wymagań i zamienia ją w przypadki testowe. Na początku wydawało się, że głównym wyzwaniem będzie dobranie modelu i napisanie dobrego promptu. Pomiary pokazały coś innego: największym problemem jest sprawdzenie, czego model nie przetestował.

Ten sam model Qwen3.6-27B, na tej samej dokumentacji, w dwóch uruchomieniach wygenerował zupełnie inne zestawy testów. Jeden obejmował 82% wymagań, drugi zaledwie 56%. Bez osobnego pomiaru pokrycia trudno byłoby zauważyć, jak wiele brakuje.

To zmieniło sposób, w jaki podszedłem do całego projektu.

Najpierw wymagania, potem testy

Zamiast polegać wyłącznie na tym, co model sam zdecyduje się przetestować, dodałem osobny mechanizm kontroli pokrycia.

Najpierw wyciągam z dokumentacji rejestr funkcjonalności. Każda musi mieć odniesienie do rzeczywistego fragmentu źródła. Następnie generuję przypadki testowe, porównuję je z rejestrem i dogenerowuję brakujące scenariusze.

W prototypie ten mechanizm podniósł pokrycie najsłabszego przebiegu z 56% do 99%. To wynik konkretnego testu, nie dowód, że na dowolnej dokumentacji osiągnę podobny rezultat.

Szczególnie ciekawy był przypadek zrzutu ekranu. Model wizyjny poprawnie opisał elementy interfejsu, ale bez kontroli pokrycia dalszy pipeline przygotował test tylko dla jednego z siedmiu elementów. Informacja została więc rozpoznana, lecz zgubiona na kolejnym etapie.

Wniosek jest prosty: poprawna ekstrakcja wymagań nie oznacza jeszcze, że powstaną dla nich testy. Trzeba sprawdzać cały przepływ.

Jak zbudowałem generator

Narzędzie działa jako lokalna aplikacja webowa. Przyjmuje dokumentację w PDF, DOCX, Excelu i plikach tekstowych. Potrafi również analizować grafiki za pomocą modelu wizyjnego.

Na wyjściu przygotowuje manualne przypadki testowe, scenariusze E2E, kod testów automatycznych oraz raport jakości. Może też korzystać z istniejących testów i przykładów, żeby zachować ich styl albo przetłumaczyć automatyzację na inny framework.

Przygotowałem dwa sposoby realizacji tego zadania.

Pierwszy to skryptowy pipeline. Dzieli dokumentację na fragmenty, wyciąga ścieżki testowe, sprawdza pokrycie i generuje scenariusze. Kolejność pracy kontroluje kod, a model wykonuje poszczególne zadania.

Drugi to agent kodujący, któremu powierzam przygotowanie testów. Ma większą swobodę w organizowaniu pracy.

Całość korzysta z API zgodnego z OpenAI przez LiteLLM. Mogę uruchamiać modele przez llama.cpp, vLLM, Ollama albo zewnętrzne API. Domyślnym założeniem jest jednak praca offline, na lokalnej infrastrukturze.

Sprawdziłem też, jak radzą sobie mniejsze modele.

Gemma 4 12B działała stabilnie na RTX 3060 z 12 GB pamięci, choć generowała mniej scenariuszy. Qwen 9B z włączonym myśleniem miał poważny problem: treść rozumowania przedostawała się do JSON i psuła wynik. Podobny problem wystąpił na większym Qwenie.

Dodanie możliwości wyłączenia myślenia dla konkretnego wdrożenia rozwiązało ten problem w zmierzonym przebiegu.

Mniejszy model potrafił też wystawić własnym, bardzo niekompletnym wynikom ocenę „100% bardzo dobra”. Dlatego wprowadziłem osobnego krytyka z innej rodziny modeli. Nie zapewnia to niezależnej oceny, ale ogranicza ryzyko powielania tych samych błędów.

Pipeline kontra agent

To był najciekawszy eksperyment.

Uruchomiłem oba podejścia na tym samym zestawie dokumentów. Kryteria oceny przygotowałem wcześniej, a pokrycie mierzył osobny skrypt.

Skryptowy pipeline osiągnął średnio 82% pokrycia wzorcowej listy wymagań, a agent 32%.

Różnica była duża, ale pipeline zapłacił za nią czasem. Pracował godzinami i wykonywał około dwunastu razy więcej wywołań modelu. Agent kończył w kilka minut.

Żeby sprawdzić, czy przewaga wynika wyłącznie z większej liczby testów, porównałem również ograniczone zestawy. Pipeline nadal prowadził.

Zauważyłem przy tym istotną różnicę. Pipeline częściej przenosił do scenariuszy konkretne wartości, identyfikatory i godziny zapisane w dokumentacji. Agent częściej opisywał ogólne zachowanie systemu.

Nie oznacza to jednak, że pipeline jest bezdyskusyjnie lepszy.

Na dużym, fikcyjnym dokumencie wygenerował setki scenariuszy, ale pracował ponad dziewięć godzin. Agenci przygotowali znacznie mniejsze zestawy. Nie stwierdzono w nich halucynacji, a niezależny sędzia wyżej ocenił jakość wyniku agenta z dużym modelem.

Zestawy okazały się komplementarne. Pipeline produkuje przede wszystkim liczne, szczegółowe mikroprzepływy. Agent przygotowuje mniej testów, ale jego wynik może zostać wyżej oceniony jakościowo.

Pozostał również problem powtarzalności. Pipeline przy kolejnych uruchomieniach na tych samych dokumentach generował bardzo różne liczby ścieżek testowych. Liczba ścieżek pozostaje niepowtarzalna.

Cytat z dokumentacji nie zawsze jest cytatem

Osobno sprawdziłem, czy agent potrafi podawać dosłowne cytaty z dokumentacji jako uzasadnienie wygenerowanych testów.

Początkowo większość takich cytatów nie była dosłowna. Zaostrzyłem więc instrukcję, wymagając zgodności znak w znak.

Wynik był jeszcze gorszy. Model zaczął tworzyć teksty wyglądające jak prawdziwe cytaty, poprzedzone nazwą pliku. W badanym przebiegu żaden nie był dosłowny.

To ważna lekcja: stanowczy prompt nie zastępuje weryfikacji źródła. Może tylko sprawić, że nieprawdziwy dowód będzie wyglądał bardziej wiarygodnie.

Po drodze trafiłem też na problemy infrastrukturalne. Serwer wieloprocesowy gubił wątek roboczy i przyjmował zadania, których nikt nie wykonywał. Deklarowane okno kontekstu bywało większe od rzeczywistego. Strumieniowanie potrafiło ominąć limit czasu, a porzucone zapytania nadal zajmowały zasoby serwera modelu.

Nawet ustawienie stałego seed nie zagwarantowało powtarzalnych wyników przy równoległym przetwarzaniu w llama.cpp.

Co z tego wynika

Po tych eksperymentach nie traktuję już generatora testów jako prostego wywołania LLM.

Najważniejszą częścią systemu jest kontrola tego, co model pominął. Rejestr funkcjonalności i wykrywanie brakujących scenariuszy dały mi więcej niż poprawianie promptu.

Skryptowy pipeline wygrywa obecnie pokryciem, ale jest wolny i generuje dużo drobnych testów. Agent działa szybciej i potrafi przygotować jakościowo dobry zestaw, lecz pomija znacznie więcej wymagań.

Nie mam jeszcze pełnego obrazu. Pozostają testy na docelowej Gemmie 4 31B, sprawdzenie „brudnej” dokumentacji ze skanami i trudnymi tabelami, porównanie agenta i pipeline’u na identycznym modelu oraz wymuszenie rzeczywistej weryfikacji cytatów przed zapisaniem scenariusza. Nie zmierzyłem też kosztów pracy na płatnym API.

Na razie najważniejszy wniosek jest taki: nie wystarczy zmierzyć, ile testów wygenerował model. Trzeba wiedzieć, których wymagań te testy nie obejmują.

← Wszystkie wpisy