Testowanie aplikacji wątków
W tym rozdziale dowiemy się o testowaniu aplikacji wątkowych. Dowiemy się również, jak ważne jest testowanie.
Dlaczego testować?
Zanim przejdziemy do dyskusji o znaczeniu testowania, musimy wiedzieć, czym jest testowanie. Ogólnie rzecz biorąc, testowanie to technika sprawdzania, jak dobrze coś działa. Z drugiej strony, szczególnie jeśli mówimy o programach komputerowych lub oprogramowaniu, to testowanie jest techniką uzyskiwania dostępu do funkcjonalności programu.
W tej sekcji omówimy znaczenie testowania oprogramowania. Przy tworzeniu oprogramowania przed wydaniem oprogramowania klientowi musi istnieć podwójna kontrola. Dlatego bardzo ważne jest, aby przetestować oprogramowanie przez doświadczony zespół testowy. Rozważ następujące punkty, aby zrozumieć znaczenie testowania oprogramowania -
Poprawa jakości oprogramowania
Z pewnością żadna firma nie chce dostarczać oprogramowania niskiej jakości i żaden klient nie chce kupować oprogramowania niskiej jakości. Testowanie poprawia jakość oprogramowania poprzez znajdowanie i naprawianie błędów.
Zadowolenie klientów
Najważniejszą częścią każdej firmy jest zadowolenie klientów. Dostarczając wolne od błędów i dobrej jakości oprogramowanie, firmy mogą osiągnąć satysfakcję klientów.
Zmniejsz wpływ nowych funkcji
Załóżmy, że stworzyliśmy system oprogramowania składający się z 10000 linii i musimy dodać nową funkcję, wtedy zespół programistów miałby obawy o wpływ tej nowej funkcji na całe oprogramowanie. Tutaj również testowanie odgrywa istotną rolę, ponieważ jeśli zespół testowy wykonał dobry zestaw testów, może to uchronić nas przed potencjalnymi katastrofalnymi przerwami.
Doświadczenie użytkownika
Kolejną najważniejszą częścią każdej firmy jest doświadczenie użytkowników tego produktu. Tylko testy mogą zapewnić, że użytkownik końcowy uzna produkt za prosty i łatwy w użyciu.
Zmniejszenie wydatków
Testowanie może obniżyć całkowity koszt oprogramowania poprzez znajdowanie i naprawianie błędów na etapie testowania jego rozwoju, zamiast naprawiania go po dostarczeniu. Jeśli po dostarczeniu oprogramowania wystąpi poważny błąd, zwiększy to jego wymierne koszty, powiedzmy w postaci wydatków i kosztów niematerialnych, np. Niezadowolenie klienta, negatywną reputację firmy itp.
Co przetestować?
Zawsze zaleca się posiadanie odpowiedniej wiedzy na temat tego, co ma być testowane. W tej sekcji najpierw zrozumiemy, jaki jest główny motyw testera podczas testowania dowolnego oprogramowania. Pokrycie kodu, tj. Ile wierszy kodu trafia w nasz zestaw testów podczas testowania, należy unikać. Dzieje się tak dlatego, że podczas testowania skupianie się tylko na liczbie wierszy kodów nie wnosi żadnej realnej wartości do naszego systemu. Mogą pozostać pewne błędy, które będą widoczne później na późniejszym etapie, nawet po wdrożeniu.
Rozważ następujące ważne punkty związane z tym, co przetestować -
Musimy skupić się na testowaniu funkcjonalności kodu, a nie jego pokryciu.
Najpierw musimy przetestować najważniejsze części kodu, a następnie przejść do mniej ważnych części kodu. Na pewno zaoszczędzi to czas.
Tester musi mieć wiele różnych testów, które mogą doprowadzić oprogramowanie do granic możliwości.
Podejścia do testowania współbieżnych programów
Ze względu na możliwość wykorzystania prawdziwych możliwości architektury wielordzeniowej, współbieżne systemy oprogramowania zastępują systemy sekwencyjne. W ostatnim czasie współbieżne programy systemowe są używane we wszystkim, od telefonów komórkowych po pralki, od samochodów po samoloty itp. Musimy być bardziej ostrożni przy testowaniu współbieżnych programów, ponieważ jeśli dodaliśmy wiele wątków do aplikacji jednowątkowej, już błąd, wtedy mielibyśmy wiele błędów.
Techniki testowania współbieżnych programów w znacznym stopniu koncentrują się na wyborze przeplotu, który ujawnia potencjalnie szkodliwe wzorce, takie jak warunki wyścigu, zakleszczenia i naruszenie atomowości. Poniżej przedstawiono dwa podejścia do testowania współbieżnych programów -
Systematyczne badanie
Podejście to ma na celu możliwie najszersze zbadanie przestrzeni przeplotów. Takie podejścia mogą przyjmować technikę brutalnej siły, a inne przyjmują technikę redukcji częściowego rzędu lub technikę heurystyczną do badania przestrzeni przeplotów.
Oparte na własności
Podejścia oparte na właściwościach opierają się na obserwacji, że błędy współbieżności są bardziej prawdopodobne w przypadku przeplotów, które ujawniają określone właściwości, takie jak podejrzany wzorzec dostępu do pamięci. Różne podejścia oparte na właściwościach dotyczą różnych usterek, takich jak warunki wyścigu, zakleszczenia i naruszenie atomowości, co dodatkowo zależy od jednej lub innych określonych właściwości.
Strategie testowania
Strategia testowania jest również znana jako podejście testowe. Strategia określa sposób przeprowadzania testów. Podejście testowe obejmuje dwie techniki -
Proaktywni
Podejście, w którym proces projektowania testów jest inicjowany tak wcześnie, jak to możliwe, w celu znalezienia i naprawy defektów przed utworzeniem kompilacji.
Reaktywny
Podejście, w którym testowanie rozpoczyna się dopiero po zakończeniu procesu programowania.
Przed zastosowaniem jakiejkolwiek strategii testowej lub podejścia do programu w języku Python, musimy mieć podstawowe pojęcie o rodzaju błędów, jakie może mieć program. Błędy są następujące -
Błędy składniowe
Podczas tworzenia programu może wystąpić wiele drobnych błędów. Błędy są głównie spowodowane błędami pisarskimi. Na przykład brak dwukropka lub nieprawidłowa pisownia słowa kluczowego itp. Takie błędy wynikają z błędu w składni programu, a nie z logiki. Stąd te błędy nazywane są błędami składniowymi.
Błędy semantyczne
Błędy semantyczne nazywane są również błędami logicznymi. Jeśli w programie wystąpi błąd logiczny lub semantyczny, instrukcja skompiluje się i uruchomi poprawnie, ale nie da pożądanego wyniku, ponieważ logika jest nieprawidłowa.
Testów jednostkowych
Jest to jedna z najczęściej używanych strategii testowania programów w Pythonie. Ta strategia służy do testowania jednostek lub komponentów kodu. Przez jednostki lub komponenty rozumiemy klasy lub funkcje kodu. Testowanie jednostkowe upraszcza testowanie dużych systemów programowania poprzez testowanie „małych” jednostek. Za pomocą powyższej koncepcji testowanie jednostkowe można zdefiniować jako metodę, w której poszczególne jednostki kodu źródłowego są testowane w celu określenia, czy zwracają pożądane wyniki.
W kolejnych sekcjach dowiemy się o różnych modułach Pythona do testowania jednostkowego.
unittest module
Pierwszym modułem do testów jednostkowych jest moduł unittest. Jest inspirowany przez JUnit i domyślnie zawarty w Pythonie 3.6. Obsługuje automatyzację testów, udostępnianie kodu konfiguracji i zamykania testów, agregację testów w kolekcje oraz niezależność testów od struktury raportowania.
Poniżej znajduje się kilka ważnych koncepcji obsługiwanych przez moduł unittest
Uchwyt tekstowy
Służy do skonfigurowania testu, aby można go było uruchomić przed rozpoczęciem testu i rozebrać po zakończeniu testu. Może to obejmować utworzenie tymczasowej bazy danych, katalogów itp. Potrzebnych przed rozpoczęciem testu.
Przypadek testowy
Przypadek testowy sprawdza, czy wymagana odpowiedź pochodzi z określonego zestawu danych wejściowych, czy nie. Moduł unittest zawiera klasę bazową o nazwie TestCase, której można użyć do tworzenia nowych przypadków testowych. Zawiera dwie domyślne metody -
setUp()- metoda hakowa do ustawiania osprzętu badawczego przed jej wykonaniem. Jest to wywoływane przed wywołaniem zaimplementowanych metod testowych.
tearDown( - metoda haka do dekonstrukcji urządzenia klasy po uruchomieniu wszystkich testów w klasie.
Zestaw testów
Jest to zbiór zestawów testów, przypadków testowych lub obu.
Biegacz testowy
Kontroluje uruchamianie przypadków testowych lub garniturów i zapewnia wynik użytkownikowi. Może używać graficznego interfejsu użytkownika lub prostego interfejsu tekstowego w celu zapewnienia wyniku.
Example
Poniższy program w języku Python używa modułu unittest do testowania modułu o nazwie Fibonacci. Program pomaga w obliczaniu szeregu Fibonacciego liczby. W tym przykładzie utworzyliśmy klasę o nazwie Fibo_test, aby zdefiniować przypadki testowe przy użyciu różnych metod. Te metody są dziedziczone z unittest.TestCase. Domyślnie używamy dwóch metod - setUp () i tearDown (). Definiujemy również metodę testfibocal. Nazwa testu musi zaczynać się od testu literowego. W ostatnim bloku unittest.main () udostępnia interfejs wiersza poleceń do skryptu testowego.
import unittest
def fibonacci(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
class Fibo_Test(unittest.TestCase):
def setUp(self):
print("This is run before our tests would be executed")
def tearDown(self):
print("This is run after the completion of execution of our tests")
def testfibocal(self):
self.assertEqual(fib(0), 0)
self.assertEqual(fib(1), 1)
self.assertEqual(fib(5), 5)
self.assertEqual(fib(10), 55)
self.assertEqual(fib(20), 6765)
if __name__ == "__main__":
unittest.main()
Po uruchomieniu z wiersza poleceń powyższy skrypt generuje dane wyjściowe, które wyglądają następująco:
Wynik
This runs before our tests would be executed.
This runs after the completion of execution of our tests.
.
----------------------------------------------------------------------
Ran 1 test in 0.006s
OK
Teraz, żeby było jaśniej, zmieniamy nasz kod, który pomógł w zdefiniowaniu modułu Fibonacciego.
Rozważmy następujący blok kodu jako przykład -
def fibonacci(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
Wprowadzono kilka zmian w bloku kodu, jak pokazano poniżej -
def fibonacci(n):
a, b = 1, 1
for i in range(n):
a, b = b, a + b
return a
Teraz, po uruchomieniu skryptu ze zmienionym kodem, otrzymamy następujący wynik -
This runs before our tests would be executed.
This runs after the completion of execution of our tests.
F
======================================================================
FAIL: testCalculation (__main__.Fibo_Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "unitg.py", line 15, in testCalculation
self.assertEqual(fib(0), 0)
AssertionError: 1 != 0
----------------------------------------------------------------------
Ran 1 test in 0.007s
FAILED (failures = 1)
Powyższe dane wyjściowe pokazują, że moduł nie dał żądanego wyjścia.
Moduł Docktest
Moduł docktest pomaga również w testowaniu jednostkowym. Jest również dostarczany z pythonem. Jest łatwiejszy w użyciu niż moduł unittest. Moduł unittest jest bardziej odpowiedni do złożonych testów. Aby skorzystać z modułu doctest, musimy go zaimportować. Dokumentacja odpowiedniej funkcji musi mieć interaktywną sesję Pythona wraz z wynikami.
Jeśli w naszym kodzie wszystko jest w porządku, moduł docktest nie będzie wyświetlał danych wyjściowych; w przeciwnym razie dostarczy dane wyjściowe.
Przykład
Poniższy przykład Pythona używa modułu docktest do testowania modułu o nazwie Fibonacci, który pomaga w obliczaniu szeregu Fibonacciego liczby.
import doctest
def fibonacci(n):
"""
Calculates the Fibonacci number
>>> fibonacci(0)
0
>>> fibonacci(1)
1
>>> fibonacci(10)
55
>>> fibonacci(20)
6765
>>>
"""
a, b = 1, 1
for i in range(n):
a, b = b, a + b
return a
if __name__ == "__main__":
doctest.testmod()
Widzimy, że ciąg dokumentacyjny odpowiedniej funkcji o nazwie fib zawierał interaktywną sesję Pythona wraz z wynikami. Jeśli nasz kod jest w porządku, moduł doctest nie wyświetli żadnych danych wyjściowych. Ale żeby zobaczyć, jak to działa, możemy uruchomić go z opcją –v.
(base) D:\ProgramData>python dock_test.py -v
Trying:
fibonacci(0)
Expecting:
0
ok
Trying:
fibonacci(1)
Expecting:
1
ok
Trying:
fibonacci(10)
Expecting:
55
ok
Trying:
fibonacci(20)
Expecting:
6765
ok
1 items had no tests:
__main__
1 items passed all tests:
4 tests in __main__.fibonacci
4 tests in 2 items.
4 passed and 0 failed.
Test passed.
Teraz zmienimy kod, który pomógł w zdefiniowaniu modułu Fibonacciego
Rozważmy następujący blok kodu jako przykład -
def fibonacci(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
Poniższy blok kodu pomaga w zmianach -
def fibonacci(n):
a, b = 1, 1
for i in range(n):
a, b = b, a + b
return a
Po uruchomieniu skryptu nawet bez opcji –v, ze zmienionym kodem, otrzymamy dane wyjściowe, jak pokazano poniżej.
Wynik
(base) D:\ProgramData>python dock_test.py
**********************************************************************
File "unitg.py", line 6, in __main__.fibonacci
Failed example:
fibonacci(0)
Expected:
0
Got:
1
**********************************************************************
File "unitg.py", line 10, in __main__.fibonacci
Failed example:
fibonacci(10)
Expected:
55
Got:
89
**********************************************************************
File "unitg.py", line 12, in __main__.fibonacci
Failed example:
fibonacci(20)
Expected:
6765
Got:
10946
**********************************************************************
1 items had failures:
3 of 4 in __main__.fibonacci
***Test Failed*** 3 failures.
Na powyższym wyjściu widać, że trzy testy zakończyły się niepowodzeniem.