Ocena głowicy defektów i testy dymne
Test dymny głowicy defektów weryfikuje, czy potok detekcji defektów strukturalnych TarmacView — szkielet DINOv3 + 5-etykietowa głowica MLP dla pęknięć/odprysków...
Test dymny to szybka, kompleksowa weryfikacja, czy pipeline oprogramowania wykonuje się bez awarii na reprezentatywnych danych, produkując oczekiwane wyniki. Skrypty smoke_*.py TarmacView walidują każdą fazę pipeline’u (analiza, ocena, wykrywanie spękań, defekty, badanie, wizualizacja). Obejmuje projektowanie testów dymnych, co testy dymne weryfikują w porównaniu z pełnymi testami oraz ich rolę w CI/CD.
{{
Test dymny to lekka, zautomatyzowana procedura weryfikacyjna, która wykonuje pipeline oprogramowania kompleksowo na reprezentatywnych lub minimalnych danych wejściowych, aby potwierdzić, że pipeline działa do końca bez awarii i produkuje pliki wyjściowe o oczekiwanej strukturze. Test przeprowadza binarną ocenę zaliczenia/niezaliczenia — jeśli którykolwiek krok zgłosi nieobsłużony wyjątek, nie wyprodukuje danych wyjściowych lub wygeneruje dane wyjściowe pozbawione krytycznych kolumn, test kończy się niepowodzeniem, a kompilacja jest natychmiast odrzucana.
Termin pochodzi z inżynierii sprzętowej, gdzie metafora jest dosłowna. Gdy inżynierowie po raz pierwszy włączali zasilanie nowo zmontowanej płytki drukowanej, obserwowali, czy dym nie wydobywa się z przepalonych komponentów. Jeśli pojawił się dym, płytka miała katastrofalną awarię i wszelkie dalsze testowanie było wstrzymywane. Wadliwą płytkę naprawiano lub odrzucano, zanim ktokolwiek zainwestował czas w szczegółową diagnostykę. Testowanie dymne w oprogramowaniu stosuje identyczną zasadę: uruchom kod i sprawdź, czy nie ma „dymu" — awarii, nieobsłużonych wyjątków, brakujących wyników — przed zainwestowaniem czasu w szczegółową walidację.
W kontekście pipeline’ów oprogramowania inspekcyjnego test dymny waliduje, że każdy etap łańcucha przetwarzania może zostać wykonany na reprezentatywnych danych. Dla TarmacView oznacza to podanie małego obrazu drogi startowej lub nawierzchni przez cały pipeline — od wczytywania obrazu przez wykrywanie spękań, klasyfikację defektów, ocenę nawierzchni, mapowanie geodezyjne i wizualizację — i sprawdzenie, że każdy etap produkuje wyniki bez błędów. Jest to szczególnie istotne w oprogramowaniu lotniczym, gdzie awarie pipeline’u mogą opóźnić oceny infrastruktury lotniskowej, które bezpośrednio wpływają na bezpieczeństwo lotów.
Termin test weryfikacji kompilacji (BVT) jest często używany zamiennie z testem dymnym, a Microsoft jest najwybitniejszym adoptującym tę terminologię. Wewnętrzne procesy deweloperskie Microsoftu — szczególnie dla Windows i Office — zinstytucjonalizowały testowanie dymne jako obowiązkową bramkę jakości w latach 90. Code Complete Steve’a McConnella określa „codzienną kompilację i test dymny" jako najwyższą praktykę branżową w zakresie dojrzałości ciągłej integracji. Framework Site Reliability Engineering (SRE) Google pozycjonuje testy dymne w ramach „testów systemowych" — najprostszego typu używanego specjalnie do skracania kosztownych pipeline’ów testowych.
Cel testowania dymnego jest trojaki:
Testy dymne zajmują pierwszy poziom piramidy testowania, wykonując się przed testami jednostkowymi, integracyjnymi i kompleksowymi zestawami regresyjnymi. Są zaprojektowane tak, aby kończyć się w poniżej 60 sekund dla typowego pipeline’u inspekcyjnego, co czyni je odpowiednimi do wykonywania przy każdym zatwierdzeniu kodu w CI/CD. W organizacjach o wysokiej dojrzałości oprogramowania testy dymne uruchamiane są przy każdym pushu do dowolnego brancha, nie tylko głównego, zapewniając najwcześniejsze możliwe wykrycie błędów integracyjnych.
Koncepcja testowania dymnego poprzedza inżynierię oprogramowania o dekady. Pierwsze udokumentowane użycie tego wyrażenia pojawia się w testowaniu instalacji wodno-kanalizacyjnych i pieców z XIX wieku. Producenci pieców rozpalali ogień wewnątrz nowo zmontowanego pieca, zamykali wszystkie przepustnice i obserwowali, gdzie wydobywa się dym — jeśli dym pojawiał się w niezamierzonych miejscach, piec miał wady konstrukcyjne. Ta sama logika „przyłóż minimalną moc i obserwuj, gdzie coś się psuje" migrowała do testowania elektroniki w połowie XX wieku, a wreszcie do inżynierii oprogramowania w latach 80. i 90.
Microsoft jest powszechnie uznawany za wprowadzenie testowania dymnego do głównego nurtu inżynierii oprogramowania. Pod koniec lat 90. działy Windows i Office Microsoftu przyjęły to, co nazwano testowaniem weryfikacji kompilacji (BVT), jako obowiązkowy proces bramkujący. Każda nocna kompilacja musiała przejść zestaw BVT, zanim została udostępniona wewnętrznym testerom. Jeśli BVT zakończył się niepowodzeniem, kompilacja była „zepsuta", a odpowiedzialny programista był powiadamiany niezależnie od pory dnia. Ta kultura natychmiastowej odpowiedzialności za jakość kompilacji stała się fundamentem kultury inżynieryjnej Microsoftu i została szeroko udokumentowana w dokumentacji MSDN i książkach Microsoft Press.
Taksonomia Crosslake Technologies (wywodząca się bezpośrednio z praktyki Microsoftu) rozróżnia testy dymne i BVT. Testy dymne opisywane są jako „pobieżne — zapewniają, że podstawowa funkcjonalność działa", wykonujące się w minutach i skupione na krytycznych funkcjach. BVT opisywane są jako „nadzbiór testów dymnych", które są „nieco bardziej dokładne", ale wciąż wykonują się w minutach, a nie godzinach. Obie pełnią tę samą funkcję bramkującą, ale BVT obejmują szerszy zestaw scenariuszy ścieżki krytycznej.
Google przyjęło testowanie dymne poprzez swoje praktyki SRE (Inżynieria Niezawodności Systemów). Blog testowy Google traktuje testowanie dymne jako znaną, przyjętą praktykę, skupiając się bardziej na tym, jak ważyć wyniki testów dymnych obok innych typów testów. Kultura inżynieryjna Google kładzie nacisk na precyzję w testach jednostkowych i ważone oceny ufności dla szerokich kontroli w stylu testów dymnych, traktując testy dymne jako uzupełnienie, a nie zastąpienie rygorystycznych testów jednostkowych.
W domenie oprogramowania lotniczego testowanie dymne odpowiada fazie testowania integracji sprzętu/oprogramowania opisanej w DO-178C, sekcja 6.4.3. Chociaż DO-178C nie wymienia wyraźnie „testowania dymnego", norma wymaga, aby zintegrowany system „uruchamiał się, a podstawowe funkcje działały" przed rozpoczęciem głębszych testów. Jest to funkcjonalnie identyczne z testowaniem dymnym. Dla oprogramowania inspekcji lotnisk działającego zgodnie z Załącznikiem 14 ICAO — który reguluje projektowanie i eksploatację lotnisk — testy dymne zapewniają niezawodność oprogramowania niezbędną do wsparcia ocen wskaźnika stanu nawierzchni (PCI), które zasilają systemy zarządzania bezpieczeństwem lotnisk.
Zrozumienie, gdzie testy dymne mieszczą się w szerszej taksonomii testowania, jest niezbędne do zbudowania zrównoważonej strategii zapewniania jakości. Cztery główne poziomy testowania pełnią komplementarne, ale odrębne role, każdy celując w różne tryby awarii na różnych etapach cyklu życia pipeline’u.
| Wymiar | Test dymny | Test jednostkowy | Test integracyjny | Test systemowy |
|---|---|---|---|---|
| Zakres | Cały pipeline kompleksowo | Pojedyncza funkcja lub metoda | Dwa lub więcej współdziałających komponentów | Pełny system w środowisku zbliżonym do produkcyjnego |
| Dane | Minimalna reprezentatywna próbka | Zamockowane lub zastąpione dane wejściowe | Rzeczywiste, ale ograniczone dane | Dane w skali produkcyjnej |
| Czas wykonania | Sekundy do poniżej 1 minuty | Milisekundy | Minuty do godzin | Godziny do dni |
| Co wyłapuje | Awarie, brakujące wyniki, błędy importu | Błędy logiczne w obrębie funkcji | Niezgodności interfejsów, błędy protokołów | Poprawność kompleksową, wydajność |
| Zależności | Rzeczywiste (nie zamockowane) | Zamockowane lub zastąpione | Rzeczywisty podzbiór | Pełny stos produkcyjny |
| Częstotliwość | Każde zatwierdzenie w CI | Każde zatwierdzenie w CI | Na kompilację lub nocnie | Na wydanie |
| Wpływ niepowodzenia | Zatrzymuje pipeline | Izolowane do pojedynczej funkcji | Blokuje branch integracyjny | Blokuje wydanie |
Testy jednostkowe walidują, że poszczególne funkcje produkują poprawne wyniki dla danych wejściowych. Mockują wszystkie zewnętrzne zależności — bazy danych, systemy plików, usługi sieciowe, akceleratory sprzętowe. Test jednostkowy dla funkcji wykrywania spękań może weryfikować, że poprawnie identyfikuje ona spękania w syntetycznej tablicy 10×10 pikseli o znanych pozycjach spękań. Testy jednostkowe są wąskie i głębokie: weryfikują logikę pojedynczej funkcji wyczerpująco, pokrywając przypadki brzegowe, warunki graniczne i ścieżki błędów. Testy jednostkowe nie mogą jednak wyłapać błędów integracyjnych, ponieważ zależności są zamockowane — test nigdy nie ćwiczy rzeczywistego łańcucha importów, ładowania konfiguracji ani przepływu danych między modułami.
Testy integracyjne walidują, że dwa lub więcej komponentów współpracuje ze sobą poprawnie. Używają rzeczywistych, ale kontrolowanych instancji zależności. Test integracyjny dla TarmacView może weryfikować, że etap wczytywania obrazu poprawnie przekazuje dane do modelu wykrywania spękań w oczekiwanym formacie tensorowym z prawidłowym porządkiem kanałów i parametrami normalizacji. Testy integracyjne są węższe niż testy dymne pod względem zakresu pipeline’u, ale głębsze pod względem walidacji interakcji: skupiają się na konkretnych granicach komponentów, a nie na całym pipeline’ie.
Testy dymne walidują, że cały pipeline wykonuje się bez awarii. Uruchamiają każdy etap sekwencyjnie z rzeczywistymi, choć małymi danymi. Testy dymne są szerokie i płytkie — obejmują cały pipeline, ale weryfikują jedynie, że wykonanie się zakończyło i dane wyjściowe istnieją, a nie że wyniki numeryczne są poprawne. Obliczenie długości spękania zwracające 47,2 piksela zamiast prawidłowych 42,1 piksela przechodzi test dymny, o ile kolumna length_px istnieje i zawiera wartość zmiennoprzecinkową.
Testy systemowe (zwane także testami kompleksowymi) uruchamiają kompletny system z danymi w skali produkcyjnej w środowisku zbliżonym do produkcyjnego. Weryfikują, że system spełnia swoje wymagania funkcjonalne i niefunkcjonalne, w tym dokładność, wydajność i niezawodność. Testy systemowe są najdroższe w uruchamianiu i utrzymaniu i wykonują się tylko na kandydatach do wydania, a nie przy każdym zatwierdzeniu.
W piramidzie testowania testy dymne stanowią warstwę podstawową — wykonują się najpierw, najszybciej i najczęściej. Jeśli test dymny zakończy się niepowodzeniem, testy jednostkowe i integracyjne na tej kompilacji są zazwyczaj pomijane lub oznaczane jako wstępnie zawodne. Oszczędza to zasoby obliczeniowe i czas programistów poprzez szybkie wykrywanie awarii, gdy podstawowe działanie pipeline’u jest zepsute.
Skuteczne projektowanie testów dymnych koncentruje się na koncepcji reprezentatywnych minimalnych danych wejściowych — najmniejszego zestawu danych, który ćwiczy każdy etap pipeline’u bez wyzwalania przypadków brzegowych zależnych od danych. Jest to najważniejsza decyzja projektowa przy budowaniu zestawu testów dymnych.
Zasada 1: Minimalne, ale nie trywialne. Dane wejściowe muszą być wystarczająco duże, aby przejść przez każdy etap pipeline’u bez wchodzenia na ścieżki kodu omijające rzeczywistą logikę przetwarzania. Obraz o jednym pikselu jest trywialny — przejdzie przez ładowanie obrazu, ale algorytmy przetwarzania wejdą na zdegenerowane ścieżki kodu, które nigdy nie są wykonywane na rzeczywistych danych. Obraz 256×256 pikseli rzeczywistej nawierzchni drogi startowej jest minimalny, a jednocześnie reprezentatywny: ćwiczy algorytmy przetwarzania oparte na kafelkach, procedury normalizacji kolorów i ścieżki wnioskowania modeli bez wymagania nadmiernego czasu obliczeniowego.
Zasada 2: Reprezentatywne dla danych produkcyjnych. Dane wejściowe powinny mieć ten sam format pliku, głębię kolorów, strukturę metadanych i właściwości statystyczne co dane produkcyjne. Jeśli dane produkcyjne pochodzą z kamery lotniczej Phase One iXM-RS150F przechwytującej 16-bitowe pliki TIFF z osadzonymi metadanymi EXIF GPS, dane wejściowe testu dymnego muszą odpowiadać tym charakterystykom. Używanie danych syntetycznych różniących się od danych produkcyjnych niweczy cel testu dymnego, ponieważ awarie pipeline’u często wynikają z nieoczekiwanych właściwości rzeczywistych danych — brakujących tagów EXIF, nieoczekiwanych profili kolorów, niestandardowych ciągów projekcji GeoTIFF.
Zasada 3: Stałe i kontrolowane wersjami. Dane wejściowe testów dymnych muszą być przechowywane w systemie kontroli wersji wraz z kodem jako pliki binarne lub zarządzane przez Git LFS (Large File Storage). Nigdy nie powinny się zmieniać bez wyraźnego przeglądu poprzez pull requesty. Zmieniające się dane wejściowe uniemożliwiają odróżnienie regresji pipeline’u od zmian danych testowych — test dymny, który przechodzi dzisiaj, a kończy się niepowodzeniem jutro, może wskazywać zarówno na regresję kodu, jak i zmodyfikowane dane testowe. Kontrolowanie wersji danych wejściowych eliminuje tę niejednoznaczność.
Zasada 4: Szybkie w przetwarzaniu. Całkowity czas wykonania zestawu testów dymnych nie powinien przekraczać 60 sekund dla typowego pipeline’u i 3 minut dla złożonych, wieloetapowych pipeline’ów, takich jak oprogramowanie inspekcyjne. To ograniczenie determinuje rozmiar danych wejściowych. Dla pipeline’ów inspekcyjnych opartych na obrazach pojedynczy obraz 512×512 pikseli jest zazwyczaj wystarczający. Dla pipeline’ów wideo — pojedyncza klatka lub 2-sekundowy klip. Dla pipeline’ów LiDAR — pojedynczy segment linii lotu obejmujący 100 metrów nawierzchni.
Zasada 5: Zawiera znane cechy. Dane wejściowe testu muszą zawierać cechy, które każdy etap pipeline’u jest zaprojektowany do wykrywania. Test dymny do wykrywania spękań jest bezużyteczny, jeśli obraz wejściowy nie zawiera spękań — pipeline mógłby po cichu pominąć wykrywanie spękań i nadal przejść test. Dane wejściowe testów muszą być dobrane tak, aby zawierały co najmniej jeden egzemplarz każdej wykrywalnej cechy ze znanym wzorcem referencyjnym, który można wykorzystać podczas analizy awarii.
Dla pipeline’u inspekcyjnego TarmacView danymi wejściowymi testu dymnego jest pojedynczy pasek ortofotomapy RGB o rozmiarze 1024×768 pikseli nawierzchni lotniskowej, przechwycony z naziemną odległością próbkowania (GSD) 1 mm. Obraz zawiera co najmniej jedną widoczną spękanie, jeden defekt nawierzchni (np. wybojenie lub spalling) oraz wyraźne oznakowanie nawierzchni. Ten pojedynczy obraz:
Oczekiwany czas przetwarzania tego pojedynczego obrazu przez cały pipeline wynosi poniżej 30 sekund na sprzęcie CI, pozostawiając margines dla pozostałych testów dymnych w zestawie. Obraz testowy jest przechowywany w repozytorium pod ścieżką tests/data/smoke/ i jest kontrolowany wersjami przez Git LFS.
Pipeline inspekcyjny TarmacView jest walidowany przez zestaw dedykowanych skryptów testów dymnych, każdy obejmujący konkretną fazę pipeline’u. Skrypty te znajdują się w katalogu scripts/, zgodnie z konwencją nazewnictwa smoke_<faza>.py. Każdy skrypt jest zaprojektowany tak, aby można go było uruchomić zarówno samodzielnie (do debugowania podczas rozwoju), jak i jako część zestawu CI (do automatycznego bramkowania).
{{
Ten skrypt waliduje fazę analizy obrazu. Wczytuje pojedynczy reprezentatywny pasek ortofotomapy, uruchamia pełny pipeline analizy przez moduł przetwarzania obrazu i weryfikuje:
Skrypt akceptuje argument --input wskazujący obraz testowy oraz argument --output-dir określający, gdzie pipeline powinien zapisywać wyniki. Jeśli pipeline ulegnie awarii podczas dowolnego kroku przetwarzania, wyjątek jest przechwytywany, a test zwraca strukturalny raport awarii.
Ten skrypt waliduje fazę oceny stanu nawierzchni. Pobiera wynik fazy analizy (lub predefiniowany plik analizy przechowywany w kontroli wersji), uruchamia algorytm oceny stanu i weryfikuje:
pavement_id, condition_index, severity, extent, date_assessedAlgorytm oceny w TarmacView jest zgodny z normą ASTM D5340 dotyczącą obliczania PCI dla lotnisk, dostosowaną do zautomatyzowanej inspekcji opartej na obrazach. Test dymny nie weryfikuje, czy wartości PCI są numerycznie poprawne — weryfikuje jedynie, że obliczenia są wykonywane, produkują wyniki w oczekiwanym formacie i są zapisywane na dysku.
Ten skrypt waliduje fazę wykrywania spękań. Uruchamia model wykrywania spękań na obrazie testowym znanym z zawierania spękań i weryfikuje:
crack_id, length_px, width_px, orientation, confidence, classificationModel wykrywania spękań używany przez TarmacView to architektura U-Net z szkieletem ResNet-50 wytrenowana na oznakowanych obrazach nawierzchni z wielu lotnisk. Obraz wejściowy testu dymnego został specjalnie wybrany ze zbioru walidacyjnego, co oznacza, że zawiera spękania, które model widział podczas treningu, ale nie podczas ewaluacji na zbiorze testowym.
Ten skrypt waliduje fazę klasyfikacji defektów nawierzchni. Uruchamia klasyfikator defektów na obrazie testowym zawierającym znane defekty (wybojenia, spalling, łatania, wietrzenie) i weryfikuje:
defect_id, defect_type, area_px, severity, confidence, timestampKlasyfikator defektów używa architektury Mask R-CNN, która produkuje maski segmentacji instancji dla każdego wykrytego defektu. Test dymny sprawdza, czy wyjściowa maska ma prawidłowe wymiary i czy plik inwentaryzacji zawiera oczekiwane kolumny schematu. Nie sprawdza, czy klasyfikacje defektów są poprawne — to wymaga oddzielnego zestawu walidacyjnego z oznakowanymi danymi referencyjnymi.
Ten skrypt waliduje fazę mapowania geodezyjnego. Pobiera dane o spękaniach i defektach wyprodukowane przez poprzednie etapy, uruchamia moduł mapowania geodezyjnego i weryfikuje:
Moduł mapowania geodezyjnego wykorzystuje metadane georeferencyjne ortofotomapy do wykonania transformacji projekcyjnej ze współrzędnych pikseli na współrzędne geograficzne. Test dymny weryfikuje, że ta transformacja produkuje prawidłowe współrzędne geograficzne w oczekiwanym prostokącie ograniczającym dla obrazu testowego. Zdjęcie lokalizacji obrazu testowego wykonane na lotnisku stanowi wizualne odniesienie do analizy awarii.
Ten skrypt waliduje fazę wizualizacji i głowicy segmentacji — końcowy etap pipeline’u, który produkuje dane wyjściowe czytelne dla człowieka. Pobiera przetworzone wyniki pipeline’u, uruchamia mechanizm renderowania wizualizacji i weryfikuje:
Faza wizualizacji jest często pierwszym miejscem, gdzie skumulowane błędy pipeline’u stają się widoczne. Etap wykrywania spękań, który produkuje maskę w niewłaściwej przestrzeni współrzędnych, wygeneruje wizualizację, w której nakładki spękań są przesunięte względem obrazu bazowego. Test dymny wykrywa to pośrednio, jeśli renderowanie ulegnie awarii, ale to regresyjny test inspekcji wizualnej — a nie test dymny — wyłapuje regresje jakości wizualnej.
Te testy dymne są zaprojektowane do uruchamiania sekwencyjnego, ale mogą również wykonywać się niezależnie, jeśli wyniki poprzednich etapów są buforowane. Pełny zestaw kończy się w poniżej 3 minut na sprzęcie CI. Każdy test wyprowadza strukturalny raport JSON z polami:
| Pole | Typ | Opis |
|---|---|---|
test_name | string | Unikalna nazwa testu (np. „smoke_crack") |
passed | boolean | Czy test zakończył się powodzeniem (true) czy niepowodzeniem (false) |
duration_ms | integer | Czas wykonania w milisekundach |
output_files | array of strings | Ścieżki do plików wyjściowych utworzonych podczas testu |
failure_reason | string lub null | Opis przyczyny niepowodzenia, jeśli test się nie powiódł |
input_path | string | Ścieżka do danych wejściowych użytych w teście |
pipeline_version | string | SHA zatwierdzenia Git lub tag wersji kodu pipeline’u |
Uruchamiacz testów agreguje poszczególne raporty JSON w podsumowanie zestawu, które jest publikowane na dashboardzie CI i opcjonalnie wysyłane przez Slack lub e-mail w celu powiadomienia w czasie rzeczywistym.
Testy dymne są celowo wąskie w tym, co potwierdzają. Weryfikują trzy kategorie warunków i nic więcej. Ten wąski zakres jest zamierzony — utrzymuje testy szybkimi, deterministycznymi i łatwymi w utrzymaniu.
Najbardziej podstawowe twierdzenie: czy kod wykonuje się bez zgłaszania nieobsłużonego wyjątku? Obejmuje to:
Pipeline, który ulega awarii podczas uruchamiania lub w trakcie wykonania, natychmiast kończy test dymny niepowodzeniem. Przyczyna awarii jest przechwytywana z tracebacka wyjątku, dostarczając programistom bezpośredniego wskaźnika do lokalizacji awarii w kodzie.
Po zakończeniu wykonania test dymny sprawdza, czy pliki wyjściowe istnieją pod oczekiwanymi ścieżkami. Obejmuje to:
Pipeline, który deklaruje zakończenie, ale nie produkuje plików wyjściowych, kończy test dymny niepowodzeniem. Wyłapuje to ciche awarie, w których pipeline kończy działanie czysto, ale pomija krytyczne operacje zapisu z powodu błędnie skonfigurowanych ścieżek wyjściowych lub logiki warunkowej, która nieoczekiwanie daje wartość fałsz.
Dla każdego wyjścia tabelarycznego (CSV, Parquet, kolekcja cech GeoJSON) test dymny weryfikuje, że oczekiwane kolumny istnieją po nazwie. Jest to kontrola integralności strukturalnej — schemat kolumn musi odpowiadać temu, czego oczekują konsumenci downstream.
| Typ wyjścia | Wymagane kolumny |
|---|---|
| Inwentaryzacja spękań | crack_id length_px width_px orientation confidence classification |
| Inwentaryzacja defektów | defect_id defect_type area_px severity confidence timestamp |
| Ocena stanu | pavement_id condition_index severity extent date_assessed method |
| Mapowanie geodezyjne | feature_id latitude longitude geometry_type crs_epsg accuracy_m |
Test używa sprawdzenia istnienia kolumn (nie sprawdzenia typu, nie sprawdzenia zakresu wartości). Jest to zamierzone — istnienie kolumn to minimalna gwarancja integralności strukturalnej. Sprawdzenia typu i zakresu należą do testów integracyjnych i walidacyjnych, gdzie koszt ich uruchomienia jest uzasadniony głębią informacji, które dostarczają.
Czwarta kategoria weryfikacji, którą wykonują testy dymne — często pomijana — to kompatybilność formatu danych. Test dymny weryfikuje, że pliki wyjściowe mogą być odczytane przez oczekiwanych konsumentów downstream. Dla TarmacView oznacza to:
Wyłapuje to niezgodności wersji formatów — na przykład jeśli biblioteka Parquet zostanie zaktualizowana i zmieni swoje kodowanie, lub jeśli specyfikacja GeoJSON ewoluuje, a wyjście pipeline’u przestanie być zgodne.
Równie ważne jest zrozumienie, co testy dymne celowo wykluczają. Niezrozumienie tego prowadzi do fałszywego poczucia pewności co do poprawności pipeline’u — pozytywny wynik testu dymnego nie oznacza, że pipeline jest poprawny, tylko że nie jest katastrofalnie uszkodzony.
Testy dymne nie weryfikują, że obliczone wartości są poprawne. Obliczenie długości spękania zwracające 47,2 piksela zamiast prawidłowych 42,1 piksela przechodzi test dymny, o ile kolumna length_px istnieje i zawiera liczbę zmiennoprzecinkową. Walidacja dokładności należy do testów jednostkowych, gdzie poprawna wartość jest zakodowana na stałe, oraz testów integracyjnych, gdzie wyniki są porównywane z ręcznymi pomiarami certyfikowanych inspektorów.
Dla pipeline’ów inspekcji lotniczej działających zgodnie z Załącznikiem 14 ICAO dokładność numeryczna jest krytyczna, ponieważ oceny stanu bezpośrednio wpływają na priorytetyzację konserwacji i alokację budżetu. Pipeline, który przechodzi testy dymne, ale produkuje niedokładne wyniki PCI, może prowadzić do błędnych decyzji konserwacyjnych. Dlatego testy dymne są tylko pierwszą bramką — muszą być następcze przez testy walidacyjne skoncentrowane na dokładności.
Testy dymne używają reprezentatywnych, ale nieadwersarialnych danych wejściowych. Nie testują:
Obsługa przypadków brzegowych jest walidowana przez dedykowane testy przypadków brzegowych, które celowo atakują każdy warunek graniczny. Testy te są droższe w uruchamianiu i są zazwyczaj wykonywane nocnie, a nie przy każdym zatwierdzeniu.
Testy dymne weryfikują, że pipeline kończy działanie, a nie że kończy w ramach budżetu wydajnościowego. Pipeline, który zajmuje 10 sekund na obraz w testach dymnych, ale ma przetwarzać 100 obrazów na sekundę w produkcji, przechodzi testy dymne bez problemu. Walidacja wydajności wymaga dedykowanych testów porównawczych z danymi w skali produkcyjnej i asercjami czasowymi.
Dla pipeline’ów inspekcji lotnisk wydajność jest krytyczna, ponieważ lotniska przetwarzają setki obrazów nawierzchni na jedno badanie. 10-krotna regresja wydajności może nadal przechodzić testy dymne na pojedynczym obrazie, ale uczyniłaby pełne badania niewykonalnymi. Testy porównawcze wydajności z progami czasowymi są odpowiednim narzędziem do wykrywania takich regresji.
Testy dymne obejmują tylko podstawową ścieżkę wykonania. Cechy nie znajdujące się na ścieżce krytycznej — alternatywne formaty wyjściowe, opcjonalne logowanie, telemetria, ścieżki audytu, eksperymentalne funkcje eksportu — nie są objęte. Regresje w tych obszarach muszą być wyłapywane przez zestawy testów regresyjnych, które celowo atakują funkcjonalności niekrytyczne.
Testy dymne nie weryfikują, że wartości danych są wewnętrznie spójne. Na przykład test dymny sprawdza, że kolumna crack_id istnieje, ale nie weryfikuje, że wszystkie wartości crack_id są unikalne, niepuste ani mieszczą się w oczekiwanych zakresach. Walidacja jakości danych wymaga dedykowanych testów jakości danych z wykorzystaniem frameworków takich jak Great Expectations lub Pandera, które definiują kontrakty danych i walidują zestawy danych względem nich.
Testy dymne dostarczają maksymalną wartość, gdy są zintegrowane z pipeline’m ciągłej integracji i ciągłego wdrażania (CI/CD). Ich umiejscowienie w przepływie pracy pipeline’u determinuje ich skuteczność jako bramki jakości.
{{
W typowym przepływie pracy CI/CD testy dymne wykonują się na etapie weryfikacji kompilacji, bezpośrednio po kompilacji i przed wszystkimi innymi zestawami testów:
Zatwierdzenie kodu → Kompilacja → Lint → Testy jednostkowe → Testy dymne → Testy integracyjne → Testy walidacyjne → Wdrożenie
Dokładna kolejność zależy od strategii testowania projektu. Niektóre organizacje uruchamiają testy jednostkowe przed testami dymnymi, argumentując, że testy jednostkowe są szybsze i wyłapują błędy logiczne. Inne uruchamiają testy dymne jako pierwsze, argumentując, że pipeline, który ulega awarii przy podstawowym wykonaniu, powinien być odrzucony bez poświęcania czasu na testy jednostkowe. Pipeline TarmacView uruchamia testy jednostkowe i testy dymne równolegle po udanej kompilacji, ponieważ obejmują one niezależne tryby awarii i nie mają współzależności.
To umiejscowienie zapewnia, że jeśli kompilacja wyprodukuje pipeline, który ulega awarii przy podstawowym wykonaniu, żadna dalsza infrastruktura testowa nie jest zużywana. Pętla sprzężenia zwrotnego mierzona jest w minutach, a nie godzinach. Programista, który pushuje zatwierdzenie zrywające łańcuch importów, otrzymuje powiadomienie o niepowodzeniu CI w ciągu 2–3 minut, zamiast czekać 4 godziny, aż zestaw testów integracyjnych zakończy się niepowodzeniem.
Pipeline CI/CD używa twardej bramki: jeśli jakikolwiek test dymny zakończy się niepowodzeniem, pipeline zatrzymuje się i nie przechodzi do kolejnych etapów. Kompilacja jest oznaczona jako nieudana, a programiści są powiadamiani z raportem awarii testu dymnego. W domyślnej konfiguracji nie jest dozwolone żadne ręczne nadpisanie — pozytywny wynik zestawu testów dymnych jest warunkiem koniecznym do wdrożenia.
Ta logika bramki zapobiega następującym scenariuszom:
Bramka jest zaimplementowana w konfiguracji platformy CI. Dla CircleCI oznacza to skonfigurowanie zależności przepływu pracy tak, aby zadanie smoke-test było uruchamiane przed integration-test i deploy. Dla GitHub Actions oznacza to użycie słowa kluczowego needs: do wymuszenia kolejności zadań.
Testy dymne w ramach zestawu mogą być uruchamiane równolegle, jeśli testują niezależne etapy pipeline’u. Zestaw testów dymnych TarmacView używa równoległości, gdzie to możliwe:
smoke_crack.py i smoke_defect.py nie mają współzależności i mogą być wykonywane równocześnie, redukując całkowity czas zestawu o 40%smoke_analyze.py musi zostać ukończony przed smoke_assess.py, ponieważ ocena zużywa wyniki analizysmoke_survey.py zależy od wyników spękań i defektówsmoke_seg_head.py zależy od wszystkich wyników upstreamStrategia równoległego wykonywania jest skonfigurowana w YAML pipeline’u CI przy użyciu równoległości na poziomie zadań. Każde zadanie działa we własnym kontenerze z izolowanymi zależnościami, zapobiegając rywalizacji o zasoby.
Integracja CI/CD obejmuje automatyczne raportowanie z wieloma kanałami:
# .circleci/config.yml
version: 2.1
jobs:
smoke-test:
docker:
- image: tarmacview/pipeline:ci
parallelism: 3
steps:
- checkout
- run: pip install -r requirements.txt
- run: python scripts/smoke_analyze.py --input tests/data/smoke_image.tif --output-dir /tmp/smoke-output
- run:
name: "Równoległe testy dymne"
command: |
python scripts/smoke_crack.py --input tests/data/smoke_image.tif --output-dir /tmp/smoke-output &
python scripts/smoke_defect.py --input tests/data/smoke_image.tif --output-dir /tmp/smoke-output &
wait
- run: python scripts/smoke_assess.py --input /tmp/smoke-output/cracks.parquet --output-dir /tmp/smoke-output
- run: python scripts/smoke_survey.py --input /tmp/smoke-output --output-dir /tmp/smoke-output
- run: python scripts/smoke_seg_head.py --input /tmp/smoke-output --output-dir /tmp/smoke-output
- store_artifacts:
path: /tmp/smoke-output
workflows:
version: 2
build-and-test:
jobs:
- build
- unit-tests:
requires: [build]
- smoke-test:
requires: [build]
- integration-tests:
requires: [smoke-test]
- deploy:
requires: [integration-tests]
Pisanie skutecznych testów dymnych wymaga dyscypliny. Test musi być szybki, niezawodny i skoncentrowany wyłącznie na tym, co ma wykrywać. Każdy test dymny podąża za tym samym podstawowym wzorcem: uruchom etap pipeline’u, sprawdź istnienie wyników, zweryfikuj minimalną poprawność schematu, zgłoś zaliczenie/niezaliczenie w strukturalnym formacie JSON.
# smoke_crack.py — uproszczony wzorzec
import sys
import json
import time
from pathlib import Path
import pandas as pd
def test_smoke_crack(input_path: str, output_dir: str) -> dict:
result = {
"test_name": "smoke_crack",
"passed": False,
"duration_ms": 0,
"output_files": [],
"failure_reason": None,
"input_path": input_path,
"pipeline_version": "unknown"
}
start = time.time()
try:
# Krok 1: Pobierz wersję pipeline'u
from tarmacview import __version__
result["pipeline_version"] = __version__
# Krok 2: Uruchom etap pipeline'u z rzeczywistymi importami
from tarmacview.pipeline.crack import detect_cracks
output = detect_cracks(input_path, output_dir)
# Krok 3: Sprawdź, czy plik wyjściowy istnieje i nie jest pusty
output_path = Path(output["crack_mask_path"])
assert output_path.exists(), f"Plik wyjściowy nie został znaleziony: {output_path}"
assert output_path.stat().st_size > 0, f"Plik wyjściowy jest pusty: {output_path}"
result["output_files"].append(str(output_path))
# Krok 4: Sprawdź kluczowe kolumny w wyjściu tabelarycznym
if output.get("crack_inventory_path"):
inv_path = Path(output["crack_inventory_path"])
assert inv_path.exists(), f"Plik inwentaryzacji nie został znaleziony: {inv_path}"
df = pd.read_parquet(inv_path)
required_columns = [
"crack_id", "length_px", "width_px",
"orientation", "confidence", "classification"
]
for col in required_columns:
assert col in df.columns, f"Brak wymaganej kolumny: {col}"
result["output_files"].append(str(inv_path))
# Krok 5: Sprawdź, czy wymiary maski wyjściowej odpowiadają wejściu
from PIL import Image
input_img = Image.open(input_path)
mask_img = Image.open(output_path)
assert input_img.size == mask_img.size, \
f"Wymiary maski {mask_img.size} nie odpowiadają wejściu {input_img.size}"
result["passed"] = True
except Exception as e:
result["failure_reason"] = f"{type(e).__name__}: {str(e)}"
result["passed"] = False
result["duration_ms"] = int((time.time() - start) * 1000)
return result
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--input", required=True)
parser.add_argument("--output-dir", default="/tmp/smoke-output")
args = parser.parse_args()
result = test_smoke_crack(args.input, args.output_dir)
print(json.dumps(result, indent=2))
sys.exit(0 if result["passed"] else 1)
Jedna asercja na kategorię. Twierdź, że wykonanie się kończy. Twierdź, że dane wyjściowe istnieją. Twierdź, że kolumny istnieją. Nie twierdź zakresów numerycznych, dokładnych rozmiarów plików ani metryk jakości danych. Każda dodatkowa asercja zwiększa koszt utrzymania testu i zmniejsza jego niezawodność.
Używaj rzeczywistych importów. Nie mockuj modułów pipeline’u. Test dymny musi ćwiczyć rzeczywisty łańcuch importów, aby wyłapać błędy importu i brakujące zależności. Test dymny, który używa unittest.mock do tłumienia błędów importu, niweczy własny cel.
Minimalna konfiguracja i porządkowanie. Test nie powinien wymagać konfiguracji bazy danych, uruchamiania usług ani zewnętrznej konfiguracji poza plikiem danych wejściowych. Jeśli wymagana jest konfiguracja, powinna być częścią definicji zadania CI, a nie skryptu testowego. Każdy test dymny powinien być uruchamialny na laptopie programisty za pomocą pojedynczego polecenia.
Deterministyczność. Te same dane wejściowe muszą zawsze dawać ten sam wynik zaliczenia/niezaliczenia. Ziarna losowości muszą być ustalone w konfiguracji pipeline’u. Pliki danych wejściowych testów muszą być kontrolowane wersjami. Niedeterministyczne testy dymne są gorsze niż bezużyteczne — niszczą zaufanie do całej infrastruktury testowej.
TarmacView używa zautomatyzowanych testów dymnych do walidacji każdego etapu swojego pipeline'u inspekcyjnego. Skontaktuj się z nami, aby dowiedzieć się, jak utrzymujemy jakość oprogramowania dla krytycznej analizy infrastruktury lotniskowej.
Test dymny głowicy defektów weryfikuje, czy potok detekcji defektów strukturalnych TarmacView — szkielet DINOv3 + 5-etykietowa głowica MLP dla pęknięć/odprysków...
Poznaj zaawansowane koncepcje testowania wydajności oprogramowania i zapewnienia jakości (QA), w tym procesy, metodyki, narzędzia, metryki oraz praktyczne zasto...
Procedura testowa to szczegółowa, krok po kroku, udokumentowana metoda systematycznej weryfikacji zgodności, poprawności i wydajności systemów w ramach zapewnie...