W poprzedniej lekcji poznaliśmy trzy główne kategorie technik projektowania testów.
Teraz zagłębimy się w pierwszą z nich – techniki czarnoskrzynkowe.
Przypomnijmy: skupiają się one na zewnętrznym zachowaniu systemu, bazując na specyfikacji i wymaganiach, a ignorując wewnętrzną strukturę kodu.
Są to jedne z najczęściej stosowanych technik w codziennej pracy testera.
Sylabus ISTQB Foundation Level v4.0 w sekcji 4.2 (FL-4.2.1 K3, FL-4.2.2 K3, FL-4.2.3 K3, FL-4.2.4 K3) wymaga od nas nie tylko zrozumienia, ale i umiejętności praktycznego zastosowania czterech kluczowych technik czarnoskrzynkowych.
Są to:
- Podział na klasy równoważności (Equivalence Partitioning - EP)
- Analiza wartości brzegowych (Boundary Value Analysis - BVA)
- Testowanie w oparciu o tablicę decyzyjną (Decision Table Testing)
- Testowanie przejść pomiędzy stanami (State Transition Testing)
W tej lekcji szczegółowo omówimy każdą z tych technik, wyjaśnimy ich założenia, pokażemy, jak je stosować w praktyce na przykładach, oraz wskażemy, jakie korzyści przynoszą i jakie mają ograniczenia.
1. Podział na Klasy Równoważności (Equivalence Partitioning - EP)
Cel: Zredukowanie liczby przypadków testowych do zarządzalnego minimum, przy jednoczesnym zachowaniu rozsądnego pokrycia możliwych danych wejściowych i wyjściowych.
Założenie: Dane wejściowe (lub wyjściowe) systemu można podzielić na grupy (klasy równoważności), w których wszystkie elementy są traktowane przez system w ten sam sposób.
Jeśli test dla jednego elementu z klasy wykryje błąd, to testy dla innych elementów z tej samej klasy prawdopodobnie również go wykryją.
I odwrotnie – jeśli test dla jednego elementu przejdzie pomyślnie, inne elementy z tej klasy również powinny.
Jak stosować?
- Zidentyfikuj parametry wejściowe i wyjściowe: Przeanalizuj specyfikację, aby znaleźć wszystkie dane, które system przyjmuje lub generuje (np. pola formularzy, parametry API, komunikaty).
- Określ warunki dla każdego parametru: Zastanów się, jakie reguły lub ograniczenia dotyczą każdego parametru (np. typ danych, zakres wartości, dozwolone znaki, format).
- Podziel dane na klasy równoważności: Dla każdego parametru utwórz co najmniej dwie grupy:
- Poprawne klasy równoważności (Valid Equivalence Partitions): Zawierają wartości, które system powinien zaakceptować i przetworzyć zgodnie ze specyfikacją.
- Niepoprawne klasy równoważności (Invalid Equivalence Partitions): Zawierają wartości, które system powinien odrzucić, zignorować lub obsłużyć jako błąd (np. wartości spoza zakresu, nieprawidłowy format, niedozwolone znaki).
- Wybierz wartości testowe: Z każdej zidentyfikowanej klasy równoważności wybierz co najmniej jedną reprezentatywną wartość do przetestowania.
- Zaprojektuj przypadki testowe: Stwórz przypadki testowe, które używają wybranych wartości. Zazwyczaj dąży się do pokrycia jak największej liczby poprawnych klas w jednym przypadku testowym, ale każdą niepoprawną klasę testuje się osobno, aby uniknąć maskowania błędów (sytuacji, gdy jeden błąd uniemożliwia wykrycie innego).
Przykład: Pole do wprowadzania wieku użytkownika, które akceptuje liczby całkowite od 18 do 65.
- Poprawne klasy równoważności:
- Liczby całkowite od 18 do 65 (np. wybieramy 30)
- Niepoprawne klasy równoważności:
- Liczby całkowite mniejsze niż 18 (np. wybieramy 17)
- Liczby całkowite większe niż 65 (np. wybieramy 66)
- Wartości niebędące liczbami całkowitymi (np. 25.5, "abc", puste pole)
Przypadki testowe:
- Wprowadź wiek 30 (oczekiwany rezultat: akceptacja).
- Wprowadź wiek 17 (oczekiwany rezultat: odrzucenie/błąd).
- Wprowadź wiek 66 (oczekiwany rezultat: odrzucenie/błąd).
- Wprowadź wiek 25.5 (oczekiwany rezultat: odrzucenie/błąd).
- Wprowadź "abc" (oczekiwany rezultat: odrzucenie/błąd).
- Pozostaw pole puste (oczekiwany rezultat: odrzucenie/błąd, jeśli pole jest wymagane).
Pokrycie: Celem jest pokrycie 100% zidentyfikowanych klas równoważności (każda klasa testowana co najmniej raz).
Mierzy się je jako (liczba przetestowanych klas / całkowita liczba klas) * 100%.
Korzyści: Znacząca redukcja liczby testów, systematyczne podejście do wyboru danych testowych.
Ograniczenia: Nie uwzględnia interakcji między różnymi parametrami wejściowymi; zakłada, że wszystkie wartości w klasie są traktowane identycznie, co nie zawsze jest prawdą, szczególnie blisko granic.
2. Analiza Wartości Brzegowych (Boundary Value Analysis - BVA)
Cel: Uzupełnienie podziału na klasy równoważności poprzez skupienie się na wartościach granicznych (brzegowych) tych klas.
Założenie: Doświadczenie pokazuje, że błędy programistyczne często występują na granicach klas równoważności (np. przy porównaniach typu >, <, >=, <=).
BVA koncentruje się na testowaniu tych właśnie „krawędzi”.
Jak stosować?
- Zidentyfikuj klasy równoważności: Wykonaj podział na klasy równoważności (EP) jak opisano powyżej. Interesują nas głównie klasy z uporządkowanymi wartościami (np. liczby, daty, zakresy znaków).
- Zidentyfikuj granice: Dla każdej uporządkowanej klasy równoważności (zarówno poprawnej, jak i niepoprawnej) zidentyfikuj jej wartości graniczne (minimalną i maksymalną wartość w klasie).
- Wybierz wartości testowe: Istnieją dwa główne podejścia:
- BVA dwuwartościowe (Two-value BVA): Dla każdej granicy wybierz dwie wartości: samą wartość graniczną i wartość tuż obok niej po drugiej stronie granicy (np. jeśli granica to 18, testuj 17 i 18).
- BVA trójwartościowe (Three-value BVA): Dla każdej granicy wybierz trzy wartości: wartość tuż przed granicą, samą granicę i wartość tuż za granicą (np. jeśli granica to 18, testuj 17, 18 i 19). Jest to podejście bardziej dokładne i częściej zalecane.
- Zaprojektuj przypadki testowe: Stwórz przypadki testowe używające wybranych wartości brzegowych. Podobnie jak w EP, testuj niepoprawne wartości brzegowe osobno.
Przykład (kontynuacja pola wieku 18-65):
Granice to 18 i 65.
Wartości testowe dla BVA trójwartościowego:
- Dolna granica (18): Testuj 17 (niepoprawna), 18 (poprawna), 19 (poprawna).
- Górna granica (65): Testuj 64 (poprawna), 65 (poprawna), 66 (niepoprawna).
Przypadki testowe (uzupełniające EP):
- Wprowadź wiek 18 (oczekiwany rezultat: akceptacja).
- Wprowadź wiek 19 (oczekiwany rezultat: akceptacja).
- Wprowadź wiek 64 (oczekiwany rezultat: akceptacja).
- Wprowadź wiek 65 (oczekiwany rezultat: akceptacja).
- (Wartości 17 i 66 były już w EP).
Pokrycie: Celem jest pokrycie 100% zidentyfikowanych wartości brzegowych. Mierzy się je jako (liczba przetestowanych wartości brzegowych / całkowita liczba wartości brzegowych) * 100%.
Korzyści: Skuteczne wykrywanie błędów związanych z obsługą granic zakresów, uzupełnia EP.
Ograniczenia: Nadal nie uwzględnia kombinacji parametrów; zakłada, że granice są dobrze zdefiniowane.
3. Testowanie w Oparciu o Tablicę Decyzyjną (Decision Table Testing)
Cel: Systematyczne testowanie złożonych reguł biznesowych, które zależą od kombinacji różnych warunków wejściowych.
Założenie: Logikę biznesową można przedstawić w formie tabeli, gdzie kolumny reprezentują warunki (wejścia) i akcje (wyjścia/zachowania), a wiersze reprezentują reguły (kombinacje warunków prowadzące do określonych akcji).
Jak stosować?
- Zidentyfikuj warunki i akcje: Przeanalizuj specyfikację, aby znaleźć wszystkie warunki (zazwyczaj logiczne, np. Tak/Nie, Prawda/Fałsz), które wpływają na decyzje systemu, oraz wszystkie możliwe akcje, które system może podjąć w odpowiedzi.
- Stwórz szkielet tabeli: Narysuj tabelę. W górnej części umieść wiersze dla warunków, a w dolnej dla akcji.
- Określ możliwe kombinacje warunków: Wypełnij kolumny tabeli wszystkimi możliwymi kombinacjami wartości warunków (np. dla N warunków binarnych będzie 2^N kombinacji). Każda kolumna reprezentuje jedną regułę.
- Określ akcje dla każdej reguły: Dla każdej kolumny (reguły) określ, jakie akcje powinny zostać wykonane, gdy dana kombinacja warunków jest spełniona. Oznacz odpowiednie pola w sekcji akcji (np. 'X' lub '✓').
- Uprość tabelę (opcjonalnie): Czasami można połączyć kolumny (reguły), które mają te same akcje, a różnią się tylko w warunkach, które nie wpływają na wynik (oznaczane jako '-' lub 'N/A' - nie dotyczy).
- Zaprojektuj przypadki testowe: Każdą kolumnę (regułę) w (potencjalnie uproszczonej) tabeli decyzyjnej przekształć w co najmniej jeden przypadek testowy. Przypadek testowy powinien realizować daną kombinację warunków i weryfikować, czy system wykonuje oczekiwane akcje.
Przykład: Logowanie do systemu. Warunki: Poprawny login (T/F), Poprawne hasło (T/F). Akcje: Zaloguj (X), Wyświetl błąd (X).
| Warunki | Reguła 1 | Reguła 2 | Reguła 3 | Reguła 4 |
|----------------|----------|----------|----------|----------|
| Poprawny login | T | T | F | F |
| Poprawne hasło | T | F | T | F |
|----------------|----------|----------|----------|----------|
| Akcje | | | | |
| Zaloguj | X | | | |
| Wyświetl błąd | | X | X | X |
Przypadki testowe:
- Podaj poprawny login i poprawne hasło (oczekiwane: zalogowanie).
- Podaj poprawny login i niepoprawne hasło (oczekiwane: błąd).
- Podaj niepoprawny login i poprawne hasło (oczekiwane: błąd).
- Podaj niepoprawny login i niepoprawne hasło (oczekiwane: błąd).
Pokrycie: Celem jest pokrycie 100% reguł w tabeli decyzyjnej. Mierzy się je jako (liczba przetestowanych reguł / całkowita liczba reguł) * 100%.
Korzyści: Systematyczne podejście do testowania złożonej logiki, pomaga zidentyfikować brakujące lub sprzeczne reguły.
Ograniczenia: Liczba reguł rośnie wykładniczo wraz z liczbą warunków, co może prowadzić do bardzo dużych tabel; trudne do zastosowania, gdy warunki nie są binarne lub gdy kolejność ma znaczenie.
4. Testowanie Przejść Pomiędzy Stanami (State Transition Testing)
Cel: Testowanie systemów, których zachowanie zależy od bieżącego stanu i zdarzeń, które mogą ten stan zmienić.
Założenie: System można zamodelować jako maszynę stanów skończonych (Finite State Machine), która przechodzi między różnymi stanami w odpowiedzi na określone zdarzenia (wyzwalacze). Przejście może być powiązane z wykonaniem określonej akcji.
Jak stosować?
- Zidentyfikuj stany: Określ wszystkie możliwe, rozłączne stany, w jakich może znajdować się system lub jego komponent (np. Włączony, Wyłączony, Zablokowany, Oczekujący).
- Zidentyfikuj zdarzenia (wyzwalacze): Określ zdarzenia, które mogą powodować przejścia między stanami (np. Naciśnięcie przycisku, Otrzymanie komunikatu, Upłynięcie czasu, Wprowadzenie danych).
- Zidentyfikuj przejścia: Określ, które zdarzenia powodują przejścia z których stanów do których stanów.
- Zidentyfikuj akcje (opcjonalnie): Określ akcje wykonywane podczas przejść lub w poszczególnych stanach.
- Stwórz model stanu: Narysuj diagram stanów (graf, gdzie węzły to stany, a krawędzie to przejścia oznaczone zdarzeniami/akcjami) lub tabelę przejść stanów (macierz, gdzie wiersze to stany, kolumny to zdarzenia, a komórki pokazują stan docelowy i akcję).
- Zaprojektuj przypadki testowe: Celem jest pokrycie różnych elementów modelu. Typowe poziomy pokrycia:
- Pokrycie stanów (All states coverage): Zaprojektuj testy tak, aby odwiedzić każdy stan co najmniej raz (najsłabsze pokrycie).
- Pokrycie przejść (All transitions coverage / 0-switch coverage): Zaprojektuj testy tak, aby wykonać każde możliwe przejście co najmniej raz (częściej stosowane).
- Pokrycie sekwencji przejść (n-switch coverage): Zaprojektuj testy tak, aby pokryć sekwencje n kolejnych przejść (bardziej zaawansowane).
Przykład: Prosty PIN (3 próby). Stany: Oczekujący na PIN, Zablokowany. Zdarzenia: Wprowadź poprawny PIN, Wprowadź niepoprawny PIN.
Diagram/Tabela:
- Ze stanu 'Oczekujący':
- Zdarzenie 'Poprawny PIN' -> Przejście do stanu 'Odblokowany' (Akcja: Zezwól na dostęp)
- Zdarzenie 'Niepoprawny PIN' (próba 1, 2) -> Pozostaje w stanie 'Oczekujący' (Akcja: Zmniejsz licznik prób)
- Zdarzenie 'Niepoprawny PIN' (próba 3) -> Przejście do stanu 'Zablokowany' (Akcja: Wyświetl komunikat o blokadzie)
- Ze stanu 'Zablokowany':
- Brak przejść (lub np. zdarzenie 'Odblokuj przez administratora')
Przypadki testowe (dla pokrycia przejść):
- Start -> Wprowadź poprawny PIN (Testuje przejście Oczekujący -> Odblokowany).
- Start -> Wprowadź niepoprawny PIN (Testuje przejście Oczekujący -> Oczekujący, próba 1).
- Start -> Niepoprawny PIN -> Niepoprawny PIN (Testuje przejście Oczekujący -> Oczekujący, próba 2).
- Start -> Niepoprawny PIN -> Niepoprawny PIN -> Niepoprawny PIN (Testuje przejście Oczekujący -> Zablokowany).
Pokrycie: Celem jest pokrycie 100% stanów lub (częściej) 100% przejść. Mierzy się je jako (liczba przetestowanych stanów/przejść / całkowita liczba stanów/przejść) * 100%.
Korzyści: Skuteczne w testowaniu systemów sterowanych zdarzeniami, pomaga wizualizować i zrozumieć zachowanie systemu, wykrywa błędy związane z nieprawidłowymi lub brakującymi przejściami.
Ograniczenia: Przydatne tylko dla systemów, które mają wyraźne stany; modelowanie złożonych systemów może być trudne i czasochłonne.
Podsumowanie
Techniki czarnoskrzynkowe są fundamentalnym narzędziem w arsenale testera.
Podział na klasy równoważności i analiza wartości brzegowych pomagają efektywnie testować dane wejściowe i wyjściowe.
Tablice decyzyjne pozwalają systematycznie weryfikować złożone reguły biznesowe.
Testowanie przejść między stanami jest idealne dla systemów sterowanych zdarzeniami.
Umiejętność wyboru i zastosowania odpowiedniej techniki (lub ich kombinacji) w zależności od kontekstu jest kluczowa dla skutecznego testowania.