Co to jest testowanie mutacji? (Przykład)
⚡ Inteligentne podsumowanie
Testowanie mutacyjne polega na celowym wprowadzaniu niewielkich błędów do kodu źródłowego, a następnie uruchamianiu istniejącego zestawu testów dla każdej wadliwej wersji, sprawdzając, czy testy są wystarczająco silne, aby wykryć zmianę.
Co to jest testowanie mutacji?
Testy mutacji Testowanie mutacyjne to rodzaj testowania oprogramowania, w którym pewne fragmenty kodu źródłowego są modyfikowane (mutowane) w celu sprawdzenia, czy przypadki testowe są w stanie wykryć błędy w kodzie źródłowym. Celem testowania mutacyjnego jest zapewnienie jakości przypadków testowych pod względem odporności, tak aby nie dały one rezultatu w przypadku zmutowanego kodu źródłowego.
Zmiana wprowadzona w programie mutacyjnym musi być minimalna, aby nie wpływała na ogólny cel programu. Testowanie mutacyjne nazywane jest również strategią testowania opartą na błędach, ponieważ polega na celowym tworzeniu błędu w programie. Jest to forma… Biały Box Testy który jest stosowany głównie podczas Testów jednostkowych.
Testowanie mutacji zostało zaproponowane w 1971 roku w pracy studenckiej Richarda Liptona i sformalizowane w artykule z 1978 roku „Hints on Test Data Selection” autorstwa DeMillo, Liptona i Saywarda. Straciło ono popularność ze względu na ówczesne koszty obliczeniowe i od tego czasu zyskało popularność w takich językach jak: Java, C#, Python, JavaSkrypt i XML.
Jak przeprowadzić test mutacji?
Poniżej przedstawiono kroki umożliwiające przeprowadzenie testu mutacji, znanego również jako analiza mutacji:
Krok 1: Błędy wprowadza się do kodu źródłowego programu poprzez tworzenie wielu wersji zwanych mutantami. Każdy mutant powinien zawierać jeden błąd, a celem jest spowodowanie awarii wersji zmutowanej, co demonstruje skuteczność przypadków testowych.
Krok 2: Przypadki testowe stosuje się zarówno do programu oryginalnego, jak i do programu zmutowanego. Przypadek testowy powinien być odpowiedni i jest dostosowany do wykrywania błędów w programie.
Krok 3: Porównaj wyniki programu oryginalnego i zmutowanego.
Krok 4: Jeśli program oryginalny i program zmutowany generują różne wyniki, to mutant zostaje usunięty przez przypadek testowy. Zatem przypadek testowy jest wystarczająco dobry, aby wykryć różnicę między programem oryginalnym a zmutowanym.
Krok 5: Jeśli program oryginalny i program mutant generują ten sam wynik, mutant jest utrzymywany przy życiu. W takich przypadkach konieczne jest stworzenie bardziej efektywnych przypadków testowych, które usuną wszystkie mutanty.
Poniższy diagram tracto te same pięć kroków – od oryginalnego programu, poprzez generowanie mutantów, aż do werdyktu o zabiciu lub przeżyciu.
Jak tworzyć zmutowane programy?
Mutacja to nic innego jak pojedyncza zmiana składniowa wprowadzona do instrukcji programu. Każdy program zmutowany powinien różnić się od programu oryginalnego dokładnie jedną mutacją.
| Oryginalny program | Program mutantów |
| Jeśli (x>y) Wydrukuj „Witam” Więcej Drukuj „Cześć” |
Jeśli (x Wydrukuj „Witam” Więcej Drukuj „Cześć” |
W powyższej parze zmienił się tylko operator porównania, ale przypadek testowy, w którym x jest większe od y, teraz wyświetla „Hi” zamiast „Hello”. Ilustracja pokazuje tę jedną zmianę składniową.
Co zmienić w programie Mutant?
Istnieje kilka technik, które można wykorzystać do generowania programów mutantów. Trzy poniższe rodziny obejmują większość operatorów mutacji, z którymi dostarczane są narzędzia.
| Operaoperatorzy zastępczy | Operatorzy modyfikacji wyrażeń | Operatorzy modyfikacji instrukcji |
| Zastąp operand innym operandem (x na y lub y na x) lub stałą wartością. | Zastąp operator lub wstaw nowy operator w poleceniu programu. | Instrukcje programowe są modyfikowane w celu utworzenia zmutowanych programów. |
| Przykład: Jeśli(x>y) zamień wartości x i y Jeśli(5>y) zamień x na stałą 5 |
Przykład: Jeśli(x==y) Możemy zastąpić == przez >= i mieć program mutanta jako If(x>=y) i wstawienie ++ w instrukcji Jeśli(x==++y) |
Przykład: Usuń część else w instrukcji if-else Usuń całe polecenie if-else, aby sprawdzić, jak zachowuje się program |
Przykładowe operatory mutacji:
- Wymiana etykiety GOTO
- Wymiana wyciągu zwrotnego
- Usunięcie oświadczenia
- Wstawianie operatora jednoargumentowego (takiego jak – i ++)
- Wymiana złącza logicznego
- Porównywalna zamiana nazw tablic
- Usuwanie części else z instrukcji if-else
- Dodawanie lub zastępowanie operatorów
- Zastąpienie wyciągu poprzez zmianę danych
- Modyfikacja danych dla zmiennych
- Modyfikacja typów danych w programie
Operamutacje, które spełniają warunek brzegowy, przeżywają najczęściej, więc wyniki mutacji często wskazują na luki w analiza wartości brzegowych.
Rodzaje testów mutacji
In Inżynieria oprogramowaniaTestowanie mutacji można zasadniczo podzielić na trzy typy — mutację instrukcji, mutację wartości i mutację decyzji.
- Mutacja wypowiedzi – polecenie jest wycinane, wklejane lub usuwane, więc wynikiem może być usunięcie kilku linii kodu.
- Mutacja wartości – modyfikowane są wartości parametrów podstawowych i stałych, np. zmieniana jest granica pętli lub próg.
- Mutacja decyzyjna – instrukcje sterujące są zmieniane, na przykład flipping operator relacyjny lub negujący warunek.
Narzędzia grupują swoje operatory pod tymi trzema nagłówkami, więc rodzina, która wygenerowała przetrwałego mutanta, informuje testera, jakiego rodzaju asercji brakuje. Przetrwały mutant decyzyjny zazwyczaj oznacza nieprzetestowaną gałąź, która nakłada się na… testowanie pętli.
Automatyzacja testowania mutacji
Testowanie mutacji jest niezwykle czasochłonne i skomplikowane do wykonania ręcznie, dlatego zaleca się korzystanie z narzędzi automatyzujących, które również obniżają koszty. Narzędzie do analizy mutacji kompiluje mutanty, planuje przebiegi, rejestruje, który mutant został wyeliminowany przez każdy nieudany test, i raportuje wynik.
Lista dostępnych narzędzi:
- Stryker — otwartoźródłowe środowisko testowania mutacji z edycjami dla JavaSkrypt i TypeScript (StrykerJS), C# i .NET (Stryker.NET) oraz Scala (Stryker4s).
- PIT, również nazywany PITest — system testowania mutacji dla Java i JVM, która modyfikuje skompilowany kod bajtowy i łączy się z Mavenem i Gradle buduje obok JUnit.
Oba działają jako krok kompilacji, więc należą do tego samego ciągła integracja rurociąg jak reszta testowanie automatyzacji na.
Wynik mutacji
Wynik mutacji definiuje się jako odsetek zabitych mutantów w stosunku do całkowitej liczby mutantów.
Wynik mutacji = (zabite mutanty / całkowita liczba mutantów) * 100
Poniżej przedstawiono wzór w formie, w jakiej zgłasza go większość narzędzi.
Przypadki testowe określa się jako mutację adekwatną, gdy wynik osiąga 100 procent. W praktyce mianownik musi wykluczać równoważne mutanty — mutanty, których zmieniona składnia zachowuje się dokładnie tak samo jak oryginał, więc żaden test nie może ich usunąć. Dlatego narzędzia raportują liczbę usuniętych mutantów podzieloną przez liczbę usuniętych plus pozostałych przy życiu mutantów nierównoważnych i pozwalają testerowi oznaczyć równoważne mutanty.
Wyniki eksperymentów wykazały, że testowanie mutacji jest skutecznym sposobem pomiaru adekwatności przypadków testowych. Główną wadą jest koszt generowania mutantów i wykonywania każdego przypadku testowego dla każdego z nich.
Testowanie mutacji vs. Code Pokrycie
Wysoki pokrycie testu Nie dowodzi to silnych testów. Pokrycie linii i gałęzi rejestruje, które instrukcje zostały wykonane, a nie to, czy cokolwiek zostało później zweryfikowane, więc test, który wywołuje metodę i nic nie potwierdza, nadal jest uznawany za pokryty. Testowanie mutacji wypełnia tę lukę, ponieważ mutant ginie dopiero wtedy, gdy potwierdzenie faktycznie się nie powiedzie.
| WYGLĄD | Code pokrycie | Wynik mutacji |
| Co mierzy | Które linie lub gałęzie zostały wykonane przez testy | Które błędy wtryskiwane wykryły testy |
| Wrażliwy na twierdzenia | Nie — test z zerową liczbą asercji nadal zwiększa zasięg | Tak — mutant przeżywa, gdy żadne stwierdzenie nie zawodzi |
| Koszt biegu | Jeden test z instrumentami | Jeden test na każdego żyjącego mutanta, jak dotąd wolniejszy |
| Typowe zastosowanie | Szybka brama przy każdym zatwierdzeniu | Dokładniejsza okresowa kontrola krytycznych modułów |
| Tryb awaryjny | 100-procentowe pokrycie bez faktycznej weryfikacji | Równoważne mutanty, których nigdy nie można zabić |
Te dwie metryki się uzupełniają. Pokrycie oznacza kod, do którego nigdy nie osiągnięto; wynik mutacji oznacza kod, do którego nigdy nie sprawdzono. Oba wskaźniki dostarczają tych samych danych. proces zarządzania defektami, obok środków takich jak gęstość defektów.
Zalety testowania mutacji
Oto zalety testów mutacji:
- Jest to skuteczne podejście pozwalające uzyskać wysoki poziom pokrycia programu źródłowego.
- Testuje sam zestaw testów, czego nie robi żaden inny technika testowania oprogramowania robi bezpośrednio.
- Testowanie mutacyjne zapewnia programistom oprogramowania wysoki poziom wykrywania błędów.
- Metoda ta pozwala na wykrywanie niejednoznaczności w kodzie źródłowym i jest w stanie wykryć błędy, których zwykłe obliczenia nigdy nie wykryją.
- Ocalałe mutanty są wykonalne: każdy z nich podaje konkretną linię i konkretną zmianę, której zespół nie zauważył.
- Klienci korzystają z tych testów, otrzymując bardziej niezawodny i stabilny system.
Wady testowania mutacji
Z drugiej strony, testy mutacji mają również następujące wady:
- Testowanie mutacji jest niezwykle kosztowne i czasochłonne, ponieważ konieczne jest wygenerowanie i skompilowanie dużej liczby programów mutantów.
- Biorąc pod uwagę, że jest to czasochłonne, można śmiało powiedzieć, że testowanie takie nie może zostać przeprowadzone bez narzędzia automatyzującego.
- Każdy mutant jest testowany przez taką samą liczbę przypadków testowych, co program oryginalny, więc duża populacja mutantów musi zostać przetestowana w całym zestawie testów.
- Mutantów równoważnych nie da się zabić żadnym testem, a oddzielenie ich od prawdziwych ocalałych zazwyczaj wymaga ręcznej analizy.
- Ponieważ metoda ta zmienia kod źródłowy, nie nadaje się do zastosowania Czarny Box Testy.
Kiedy stosować testy mutacji
Powyższy profil kosztów oznacza, że testy mutacyjne rzadko przeprowadza się na całej bazie kodu przy każdym zatwierdzeniu. Opłacają się one, gdy niewykryty błąd jest kosztowny, a testowany kod jest na tyle mały, że szybko ulega mutacji.
- Krytyczne dla bezpieczeństwa lub logika finansowa — obliczanie płatności, zasady podatkowe i kontrole autoryzacji, gdzie jedna błędna odpowiedź może być gorsza niż awaria.
- Apartamenty z podejrzanie wysokim zasięgiem — gdy pokrycie wynosi prawie 100 procent, ale nadal pojawiają się defekty.
- Przebudowa starego kodu — wyniki mutacji ujawniają, czy istniejące testy wykryją regresję.
- Biblioteki i współdzielone komponenty — usterka w ponownie użytym składnik mnoży się przez każdego rozmówcę.
- Zespoły ćwiczące rozwój oparty na testach — wyniki sprawdzają, czy testy napisane jako pierwsze rzeczywiście działają.
Zwykle nie warto uruchamiać oprogramowania na prototypach jednorazowych, na cienkim kleju lub generowanym kodzie bez logiki rozgałęzień lub na pakietach zdominowanych przez wolne testy integracyjne które już na jedno przejście zajmują godziny.
Większość zespołów ogranicza zatem zakres uruchomienia do zmienionych plików, ustala próg dla modułów, które mają znaczenie, i pozwala na szersze testy regresji apartament zabierze resztę cykl życia testowania oprogramowania.



