Priorytety w testowaniu oprogramowania, analiza ryzyka

Ryzyko w testowaniu oprogramowania można określić procentowo, jako stopień niepewności czy projekt osiągnie założone cele. Ryzyko określa prawdopodobieństwo wystąpienia nieporządanej, zdefiniowanej wcześniej, sytuacji oraz stopień jej wpływu na powodzenie projektu.

Jakie ryzyka wiążą się z zastosowaniem podejścia typu Risk Based Testing?

  • niesprecyzowana defininicja ryzyka – umieszczanie ryzyk i błędów w jednej  grupie
  • subiektywna ocena wpływu ryzyka na projekt oparta na “pasujących” czynnikach
  • brak przeglądów listy ryzyk w kolejnych fazach SDLC

Testując oprogramowanie nie da się sprawdzić wszystkich scenariuszy (tak jak nie da się znaleść wszystkich błędów). Dlatego tak ważne jest podjęcie decyzji co testujemy, a czego nie. Na których obszarach aplikacji skupić uwagę, a które uznać za “niezagrożone”. Testowanie np. metodami czarnej skrzynki z użyciem klas równoważności czy wartości brzegowych zapewnia co prawda pokrycie funkcjonalności testami, ale przy okazji powoduje, że liczba przypadków testowych (test cases) rośnie. Co więcej nie wszystkie z nich są tak samo istotne z punktu widzenia jakości systemu, czasu, który mamy na testowanie oraz wymagań klienta.

Sposobem na zmniejszenie liczby przypadków testowych jest wybranie tych funkcjonalnych obszarów aplikacji, które są najbardziej podatne na błędy oraz tych, których uszkodzenie może spowodować największe koszty.

Gdzie i kiedy spodziewać się największej liczby błędów?

To tylko kilka czynników, które warto wziąć pod uwagę przy ustalaniu zakresu testów aplikacji. Moim zdaniem -ważnych, ale jak zwykle wszystko zależy od kontekstu i danego projektu.

Złożone funkcjonalności.
Złożoność jest jedną z najczęstszych przyczyn powstawania błędów: wiele zmiennych użytych w kodzie, rozłożony na wiele kroków przepływ danych, skomplikowana logika biznesowa, zgromadzenie w jednym module wielu funkcji, których interfejsy wychodzą na zewnątrz.

Obszary systemu, które zostały zmodyfikowane/przepisane.
Testy regresywne powinny załatwić sprawę. Jednak i one mają swoje priorytety, które mogą zmienić się po wprowadzeniu zmian w funkcjonalności. Innego rodzaju zagrożeniem przy wyborze scenariuszy testowych do testów regresywnych jest paradoks pestycydów.

Wiele zmian w pojedyńczym module systemu może być symptomem źle wykonanej analizy. To sygnał aby otworzyć plik z wymaganiami i przypadkami użycia (Use Cases) -jeśli mamy ich zaktualizowaną wersję :)
Liczba osób zaangażowanych w programowanie/testy.
Im więcej osób jest zaangażowanych w zadanie tym większy nakład środków i czasu na komunikację. Wydłużony przepływ informacji prowadzi do ich zniekształcenia, nadinterpretacji czy pomijania. Może działać to zarówno podczas kodowania jak i przy testach.

Jakość wykonania testów (nie mówię tu o jakości aplikacji, ale o jakości pracy) jest ważniejsza niż odpowiedź na pytanie “Zostało nam trzy tygodnie na testy. Ile dodatkowych osób możemy w nie zaangażować?”. Jedną z metryk (z pewnością nie najlepszą) wydajności testera jest liczba zgłoszonych przez niego błędów.

Trudno jest porównać trójosobowy, doświadczony zespół testowy i zgłoszone przez niego błędy ukryte w architekturze systemu z 10-cioosobową grupą nie-testerów, którzy testują w międzyczasie i chcąc wykonać przypadek testowy, a więc przejść z ekranu A na ekran B, zaglądają np. do kodu aplikacji.

Presja czasu, zarówno przy kodowaniu jak i testach.
Błędne estymacje czasu, problemy w komunikacji, sytuacje nieprzewidziane podczas fazy analizy ryzyka projektu. Wszystko to powoduje opóźnienia zarówno w fazie kodowania jak i testów. Brak czasu jest wrogiem jakości. Skłania do pomijania pierwotnie obranej ścieżki i stosowania skrótów.

Pytania jakie warto zadać przed podjęciem decyzji co testujemy:

  • które elementy aplikacji mogą zostać przetestowane we wczesnej fazie SDLC?
  • które części kodu/moduły są najbardziej skomplikowane i dlatego najbardziej narażone na wystąpienie błędów?
  • która funkcjonalność jest najważniejsza z punktu widzenia zastosowania projektu?
  • która funkcjonanlość jest najbardziej widoczna dla klienta?
  • które z testów mają najlepszy współczynnik pokrycia obszarów o wysokim ryzyku do czasu potrzebnego na testowanie?
  • które z wymagań zostały zmienione lub ogólnie zdefiniowane?
  • która funkcjonalność ma największy wpływ na bezpieczeństwo aplikacji?
  • która funkcjonalność ma największy wpływ na finanse?
  • Które elementy testowanej aplikacji mają największe znaczenie dla klienta?
  • które aspekty podobnych, ukończonych poprzednio projektów powodowały problemy?
  • które elementy podobnych, ukończonych projektów powodowały największe problemy w fazie utrzymania (maintenance)?
  • co programiści uznają na najbardziej narażony na ryzyko element aplikacji?
  • która część systemu była tworzona pod presją czasu?
  • jaki rodzaj problemów może spowodować negatywną reakcję klienta?
  • jaki rodzaj testów może pokryć możliwie najwięcej funkcjonalności?
  • które z poprzednio wykonanych przypadków testowych powodowały wykrycie błędów? (test case value)

Kiedy zakończyć testowanie aplikacji

Moment zakończenia testów oprogramowania może być trudny do określenia. Współczesne aplikacje są złożone, pracują w rozproszonym środowisku i składają się z wielu współpracujących podsystemów. Teoretycznie testy mogą trwać przez cały  SDLC oraz w fazie utrzymania.
Są jednak czynniki, które pomagają zdecydować o zakończeniu testów:

  • czas (data uruchomienia w środowisku produkcyjnym, data zakończenia testów aplikacji, tzw. deadline)
  • przypadki testowe (test cases) – odpowiedni procent przypadków testowych, których wykonanie nie spowodowało wykrycia błędu.
  • wyczerpanie budżetu na testy
  • pokrycie kodu, funkcjonalności, wymagań w założonym zakresie
  • krzywa wykrywania błędów poniżej założonego wcześniej progu

Kto zatem powinien podjąć decyzję o zakończeniu testowania?

Osobą odpowiedzialną za testy w organizacji jest Test Manager. Z punktu widzenia jakości to on podejmuje decyzję o tym czy system spełnia zdefiniowane wcześniej kryteria jakości, jednak z punktu widzenia projektu informacja ta jest jedną ze składowych, które brane są pod uwagę przed wdrożeniem wersji produkcjyjnej testowanej aplikacji:

  • daty uruchomienia współpracujących systemów
  • cele związane ze sprzedażą
  • sytuacja na rynku i poczynania konkurencji
  • czynniki prawne
  • oczekiwania klienta

Z powyższych wynika, że odpowiedzialnością Test Managera jest dostarczenie informacji nt jakości grupie osób odpowiedzialnych za podjęcie decyzji o “wypuszczeniu aplikacji na rynek”. W małych organizacjach/projektach taką rolę może pełnić Project Manager lub Product Manager. W dużych decyzja może być podejmowana przez grupę osób ze strony biznesu i projektu.

Definicje rodzajów błędów w testowaniu aplikacji

  • Error: niezgodność pomiędzy dostarczonym przes funkcję, zaobserwowanym lub zmierzonym rezultatem jej wykonania, a oczekiwaną wartością. Błędy mogą być powodowane celowo w procesie testowania aplikacji.
  • Failure: niemożność komponentu lub systemu do wykonania operacji w np. określonym w wymaganiach czasie
  • Exeption:  nieobsługiwany wyjątek, który powoduje zawieszenie lub przerwanie działania programu. Wyjątek może pojawić się w związku z adresowaniem pamięci, danymi, wykonaną operacją, przepełnieniem zmiennej, itp.
  • Defect, bug, fault: wada modułu lub systemu, która może spowodować, że moduł lub system nie wykona zakładanej czynności. Defekt, który wystąpi podczas uruchomienia programu, może spowodować awarię modułu lub systemu. (za słownikiem terminów testowych 2.0)
  • deviation, incident – każde zdarzenie występujące w procesie testowania, które wymaga zbadania (IEEE 1008)

Mity na temat testowania oprogramowania

Przetestowanie całej aplikacji/systemu jest możliwe. Jeśli testy zostaną odpowiednio zaplanowane to możliwe jest znalezienie i poprawienie wszystkich błędów w aplikacji.
Oprogramowanie zawiera coraz więcej linii kodu, staje się coraz bardziej złożone. Coraz więcej aplikacji współpracuje ze sobą w ramach jednego, rozproszonego systemu. Pokrycie testami wszystkich ścieżek przejścia we wszystkich kombinacjach jest niemożliwe choćby z powodu ograniczeń związanych z budżetem i czasem.

Kiedy projekt zakłada, że po ostatniej fazie testów aplikacja będzie wolna od błędów, dział testów staje się odpowiedzialny za każdy problem znaleziony w wersji produkcyjnej. Z kolei próba przetestowania wszystkich aspektów tworzonej aplikacji spowoduje opóźnienie w dostarczeniu wersji produkcyjnej. W rzeczywistości prawie każda aplikacja zawiera błędy. Pytanie, jakiego są one rodzaju i jak często objawiają się w np. niestabilnym działaniu gotowego produktu.

Testy powinny być przeprowadzane w pełni skonfigurowanym środowisku.
Im bardziej środowisko testowe przypomina docelowe środowisko produkcyjne, tym bardziej można polegać na wynikach testów. Jeśli środowisko produkcyjne klienta jest przez niego w pełni kontrolowane, testowanie może odbywać się w jak najbardziej zbliżonych warunkach. Jeśli tak nie jest, testy przeprowadzone w pełni skonfigurowanym środowisku mogą spowodować, że ważne przypadki testowe mogą w ogóle nie powstać.

Testowanie jest potrzebne, aby udowodnić, że oprogramowanie nie zawiera błędów.
Testowanie samo w sobie nie służy do poprawienia jakości aplikacji, ale jest tej jakości miernikiem. Przystępując do testów nie należy robić tego z założeniem, że system działa.

Zazwyczaj przypadki testowe, których wykonanie nie spowodowało wykrycia błędu oznacza się statusami “passed”, “ok”, “tested ok”. Jednak z punktu widzenia testera to właśnie Test Case, który pozwolił na odkrycie błędu jest sukcesem.
Oprogramowanie oprócz tego, że powinno poprawnie wykonywać pożądane i zaimplementowane funkcjonalności, nie powinno pozwalać na operacje, do których wykonywania nie zostało stworzone.

Automatyzacja testów. Jeśli można coś zautomatyzować należy to zrobić.
Automatyzacja jest potrzebna. Oszczędza nam, testerom długich wieczornych godzin spędzonych przy manualnych testach regresywnych. Z kolei estymowana liczba godzin na testy manualne, może skłonić projekt do zainwestowania w automatyzację testów.

Jednak co z czasem spędzonym na nauce narzędzi do testów automatycznych, tworzeniu skryptów i ich aktualizacją? Jedynie odpowiednia kombinacja testów automatycznych, testów eksploracyjnych i manualnych testów wykonywanych na podstawie przypadków testowych może spowodować, że informacja o jakości testowanego oprogramowania będzie kompletna i wiarygodna.

Metoda gumowej kaczuszki

O  metodzie dowiedziałem się za pośrednictwem testerzy.pl Zaznaczam, że jest ona skierowana do programistów, jednak nic nie stoi na przeszkodzie, aby zastosować ją przy pisaniu skryptów automatycznych czy przypadków testowych 🙂

Metoda gumowej kaczuszki – nieformalny sposób debugowania kodu. Metoda polega na tym, że programista trzyma gumową kaczuszkę lub inny przedmiot przy sobie, gdy próbuje znaleźć błędy w kodzie.

Linia po linii, programista tłumaczy kaczuszce lub innemu obiektowi, co każdy segment kodu powinien robić i podczas tej rewizji błędy logiczne lub syntaktyczne powinny wyjść na jaw.

źródło: Wikipedia

Testowanie statyczne

Jest to proces pozwalający na wyszukanie błędów od fazy zbierania wymagań biznesowych poprzez konstruowanie kodu, aż po dostarczenie produktu, jednak bez uruchamiania aplikacji.

Testy statyczne przeprowadzane są przy użyciu przeglądów (reviews) oraz analizy statycznej (static analysis).

Przeglądy
Przegląd jest procesem lub spotkaniem podczas którego produkt/system jest przedstawiany członkom zespołu projektowego, użytkownikom oraz innym zainteresowanym stronom w celu uzyskania komentarzy lub aprobaty dla danego rozwiązania.

Istnieje wiele poziomów na których można dokonywać przeglądów. Od bardzo nieformalnych spotkań do moderowanych i opisanych procedurami sesji.
Przeglądy są szeroko stosowane podczas całego cyklu wytwarzania produktu.

Zaletą przeprowadzania testów już od etapu wymagań jest (jak opisuje to V-Model), możliwość wcześniejszego wykrycia błędu co przekłada się na niższe koszty dla projektu. Drugi powód dla którego warto stosować przeglądy to to, że ten rodzaj testów nie jest zależny od dostarczonego kodu.

Przeglądy mogą dotyczyć:
– wymagań
– specyfikacji
– kodu
– strategii testów
– planu testów
– warunków koniecznych do przeprowadzenia testów
– przypadków testowych
– instrukcji użytkownika

Przeglądy są procesem iteracyjnym. Wymagania użytkownika, specyfikacja funkcjonalna i techniczna są zazwyczaj rozwijane i modyfikowane. Pierwszy przegląd wyłania pytania i nieścisłości, które zostają wyjaśnione po czym następuje kolejny przegląd.

Koszty przeglądów obejmują:
– przygotowanie do przeglądu
– przeprowadzenie przeglądu
– opracowanie wyników i raportu

Zalety przeglądów:
– podniesienie jakości dostarczanego rozwiązania
– usprawnienie procesu produkcji systemu
– redukcja czasu trwania całego projektu
– mniejszy nakład pracy na późniejszych etapach testowania
– mniejsza liczba błędów (część z nich została usunięta przed rozpoczęciem kodowania)
– obniżone koszty całego cyklu życia produktu

Dlaczego oprogramowanie zawiera defekty?

Przyczyny dla których w projekcie mogą pojawić się błędy, można przypisać do kilku grup.

Wprowadzone przez człowieka na każdym z etapów SDLC, począwszy od etapu analizy wymagań na instalacji gotowego produktu kończąc.

Sprzęt/środowisko. “Błędy” z tej grupy nie są wynikiem źle napisanego czy nieprzetestowanego kodu, ale jego brakiem, np. brak funkcji obsługującej sytuację w której zerwane zostaje połączenie sieciowe w trakcie przesyłania danych przez aplikację.

Złożoność systemu
Złożoność systemu może być trudna do zrozumienia dla kogoś bez doświadczenia w funkcjonującym dzisiaj sposobie tworzenia oprogramowania. Interfejsy wzorowane na oknach, technologia klient-serwer, aplikacje rozproszone, komunikacja danych i relacyjne bazy mają swój udział w szybko przyrastającej złożoności oprogramowania/systemów. Również użycie technik obiektowych, zamiast uprościć może skomplikować projekt jeżeli nie jest on dobrze skonstruowany.

Błędy w kodzie
Programiści jak każdy z nas, popełniają błędy. Część z nich może powstać w wyniku interpretacji źle lub niewystarczająco jasno zdefiniowanych wymagań. Zakładając, że błędów nie da się uniknąć i że zostaną one odnalezione przez testerów :) jest ważne aby być przygotowanym do zarządzania nimi za pomocą narzędzi komercyjnych np. Rational, lub opensource np. Mantis.

Zmieniające się wymagania
Klient może nie być świadomym efektów zmian lub chce je wprowadzić pomimo ryzyka z którego zdaje sobie sprawę – redefiniowanie wymagań, estymacja liczby godzin przeznaczonych na dodanie/modyfikację funkcjonalności, wpływ zmian na równoległe projekty, konieczność ponownego wykonania tej samej pracy lub porzucenia części działającego i przetestowanego już kodu, zmiana wymagań sprzętowych (zazwyczaj w górę).

Wiele drobnych lub kilka dużych zmian może wpłynąć na wytworzone (zdefiniowane lub nieformalne) zależności wewnątrz projektu i stać się przyczyną problemów, podobnie jak rosnąca złożoność procesu zarządzania.

Presja czasu
Planowanie w projektach informatycznych jest w najlepszym przypadku trudne, częściowo opiera się na przewidywaniu. Może zdarzyć się, że zbliżający się termin oddania aplikacji staje się jedynym wyznacznikiem jakości kodu.

Smoke test i Sanity test

Smoke test określa czy możliwe jest przeprowadzenie testów.
Sanity test odpowiada na pytanie czy jest to zasadne.

Smoke test

Smoke test mówi nam, czy program/system da się uruchomić, czy jego interfejsy są dostępne i czy reagują na działania użytkownika. Jeżeli smoke test nie powiedzie się nie ma powodu aby przechodzić do sanity testów. Ten typ testów przeprowadzany jest przez programistów tuż przed oddaniem wersji aplikacji lub przez testerów, przed zaakceptowaniem otrzymanej do testów aplikacji.

Pojęcie “smoke test” powstało na potrzeby testów sprzętu. Sam test polegał na włączeniu nowego urządzenia i sprawdzeniu czy nie pojawił się dym lub ogień :-)
Somke testy mogą być wykonywane na podstawie istniejących przypadków testowych lub przy użyciu narzędzi do testów automatycznych

Przeznaczeniem smoke testów jest “dotknięcie” każdej z części aplikacji bez zagłębiania się w logikę jej działania. Chodzi o upewnienie się, czy najbardziej krytyczne funkcje działają.

Sanity test

Sanity test sprawdza pojedyńcze funkcjonalności i daje odpowiedź na pytanie: czy logika aplikacji jest zgodna z dostarczonymi wymaganiami. Jeżeli przeprowadzenie sanity testu da negatywne rezultaty, nie ma powodu, aby przechodzić do następnej fazy testowania.

Sanity oraz smoke test należą do tej samej grupy testów, której atrybutami są:
– szybko,
– w szerokim zakresie,
– bez zagłębiania się w szczegóły działania testowanej funkcjonalności.

Sanity test koncentruje się na jednym lub kilku obszarach systemu badając jego zgodność z logiką biznesową.Zazwyczaj nie jest opisany w przypadkach testowych.

Jest to odmiana testów regresywnych – obszar systemu testowany jest po dokonaniu w nim znaczących zmian dotyczących sposobu jego działania.

Sanity test daje odpowiedź na pytanie czy to co testujemy jest zgodne z wymaganiami i specyfikacją systemu.

Cykl wytwarzania oprogramowania

  1. Programista tworzy kod wierząc, że nie zawiera on błędów.
  2. Dział testów znajduje 20 błędów w aplikacji.
  3. Programista poprawia 10 z nich i wyjaśnia, że pozostałych 10 to nie błędy.
  4. Dział testów odrzuca 5 z 10 poprawek i znajduje 15 nowych błędów.
  5. Cykl poprawki/retesty powtarza się 3 razy.
  6. Z powodu nacisków działu marketingu i nadmiernie optymistycznego planu developementu produkt zostaje wypuszczony.
  7. Klient znajduje 137 błędów.
  8. Programista, który stworzył system, pobrał już wynagrodzenie z kontraktu i jest nieosiągalny.
  9. Utworzony na nowo zespół programistów poprawia wszystkie ze 137 błędów, wprowadzając jednocześnie 456 nowych.
  10. Programista, który stworzył system wysyła kartkę z Fiji do niedofinansowanego działu testów. Dział testów odchodzi.
  11. Firma zostaje kupiona przez konkurencję za profity uzyskane ze sprzedaży ich ostatniej aplikacji, która zawiera 783 błędy.
  12. Nowy szef zatrudnia programistę, aby napisał ten sam program od podstaw.
  13. Programista tworzy kod wierząc, że nie zawiera on błędów…