1 2 3 4 5 6 Błędy, testowanie i weryfikacja programów Jak napisać bezbłędny program? Klasyfikacja błędów Błąd składniowy (błąd kompilacji) pomyłka (np. nieprawidłowo zapisana nazwa, brak nawiasu, itp.) Rozwiązanie: kompilator: przerywa kompilację, wskazuje miejsce, poprawia programista. Błąd czasu wykonywania (runtime error) nieoczekiwane przerwanie działającego programu (dane nieprawidłowe, niewykonalna operacja (/0), błąd zapisu ) zdarzenie zewnętrzne zmusza program do zakończenia pracy Rozwiązanie: przewidzieć!, także testować sprawdzać dane, oprogramować lub przejąć obsługę błędu Błąd logiczny (np. zliczanie zdań: sekwencja kropka-spacja; Na rys. 2 pokazano... błąd algorytmu (działa, ale źle) Rozwiązanie: stwierdzić istnienie! testować; najlepiej usunąć przed oddaniem programu po przekazaniu: powtarzalność błędu określić sekwencję operacji poprawić algorytm lub wykluczyć przypadek (ograniczyć dziedzinę) Proces a program Program jest obiektem statycznym to formalny opis tego, co ma być wykonane. Proces jest obiektem dynamicznym to ciąg sekwencyjnie wykonywanych instrukcji programu. Każdy program jest skończony trudno napisać nieskończony program Procesy mogą być: skończone (te z reguły nas interesują) nieskończone (kończone mniej lub bardziej brutalnie) Poprawność programów Poprawność częściowa - po zakończeniu: wygenerowane dane wyjściowe są poprawne (zgodne ze specyfikacją dla przyjętych danych wejściowych). Poprawność całkowita dla wszystkich dopuszczalnych zestawów danych wejściowych proces kończy swe działanie wygenerowane dane wyjściowe są poprawne (zgodne ze specyfikacja dla przyjętych danych wejściowych). Dowodzenie poprawności programów Formuły częściowej poprawności programu Anthony Hoare, połowa lat 60. Metoda dowodzenia warunku stopu (60) R. Floyd; korzysta z zasady indukcji Przykład Zadanie: czy w A[1..n] jest x? 1
bool jest = false; for (int i=1; i<n; i++) if (A[i] == x) jest = true; Dowód poprawności: 7 Dowody poprawności, ze względu na ich nietrywialność, stosuje się dla prostych algorytmów. W praktyce nie dowodzi się poprawności większych programów. 8 9 Co z tym bezbłędnym programowaniem programowanie jest dziedziną wielce zróżnicowaną, często wymagającą złożonej działalności intelektualnej. Przypuszczenie, że kiedykolwiek można by jego naukę skondensować w postaci ścisłych recept wydaje się niesłuszne. Wirth, 1989 Nie istnieją żadne absolutne reguły stylu programowania tak samo jak stylu pisania, ponieważ programowanie jest częściowo sztuką, a częściowo nauką. McCracken, Salmon, 1987 Etapy rozwoju programu Rozwiązanie zadania: 1. dokładne zdefiniowanie zadania 2. wyjaśnianie i usunięcie nieokreśloności w sformułowaniu problemu 3. wybór sposobu rozwiązania problemu 4. naszkicowanie rozwiązania w zrozumiałym zapisie - schemat rozwiązania 5. kodowanie (proces, tak naprawdę, mało twórczy ), czyli mechaniczny przekład rozwiązania problemu na poprawne gramatycznie zdania pewnego szczególnego języka (np. Pascala). 6. wyłapanie i usunięcie błędów z napisanego programu - odpluskwianie 7. napisanie i uzupełnienie dokumentacji programu 8. dokładne sprawdzenie (testowanie) programu 9. wdrożenie i utrzymanie (konserwacja) programu 10 11 Definiowanie i szkic rozwiązania Faza definiowania problemu - częsty błąd => wpływ na cały proces!: niepełne zdefiniowanie zadania programistyczne bo nie do końca rozumiem (albo potrafię dogadać się ze zleceniodawcą) pozostawienie niejasności, np.: jest jeszcze jeden przypadek, ale rzadko występuje, potem ustalimy to ustalimy na końcu (zakres raportu, eksportowanych danych, ) Szkic rozwiązania: program (nie programik ): oddzielne, ale powiązanych zadania, np. System Magazynowy: rejestracja dokumentu przychodu (obrót materiałowy, kartoteka ) rejestracja dok. rozchodu precyzyjnie określić zadania dla każdej z części programu podać związki między tymi częściami co na wejściu, co na wyjściu Efekt: wykonanie każdej z tych części z osobna =>> prawidłowa całość. Algorytm i kodowanie Wybór i reprezentacja algorytmu jak program ma rozwiązać zadanie? algorytm: sposób rozwiązania problemu: dostępny w literaturze, bibliotekach algorytmów, opracowany przez programistę 2
12 13 14 15 16 17 reprezentacja: zapis schematyczny Kodowanie wybór języka, narzędzi (zależnie od problemu, innych uwarunkowań) Testowanie, dokumentacja Faza sprawdzania - testowanie wybrać takie dane, dla których potrafimy przewidzieć wyniki dokonać wszelkich możliwych testów programu. Dokumentacja wykonywana na bieżąco (jest zajęciem ciągłym!), dokumentację tworzą wszystkie materiały z etapów poprzednich: szczegółowy opis problemu przedstawienie algorytmiczne zadania program jako taki. Dokumentacja informacje dla użytkownika dla programistów (ewentualne zmiany w przyszłości). Testowanie wskazuje na obecność błędów, nie zaś na ich brak E. Dijkstra _ Konserwacja i dostosowywanie Program to narzędzie, które należy poprawiać: błędy w różnych fazach jego powstawania dostosowywać do aktualnej sytuacji: zmiany w przepisach, różnice w konfiguracji sprzętu komputerowego, różne urządzenia wejścia-wyjścia, różnice w realizacji języków programowania dla różnych maszyn, itp. Aktualizacja dokumentacji! każda modyfikacja programu => dokładna informacja. Tylko dobrze zorganizowane programy, z przejrzystą dokumentacją, mają szanse na przetrwanie. Czas (w przybliżeniu) Definiowanie, analiza wymagań użytkownika: 10% Określenie funkcjonalności: 30% analiza zasobów systemowych, szkic dokumentacji, przewodnik użytkownika (pomaga w całym procesie pisania programu i jego konserwacji), analiza możliwych błędów i opis reakcji itp. Projektowanie programu: 20% wybór typów danych, algorytmu, podział programu na fragmenty, itd. Kodowanie: 15% zapis projektu w języku wyższego poziomu (Pascal, C++, itd.) Sprawdzanie poprawności: 15% kompilacja, usuwanie błędów, wykonanie obliczeń z danymi, które prowadzą do znanych wyników, z danymi błędnymi, przypadkowymi i rzeczywistymi Instalacja: 10% umieszczenie programu na komputerze klienta, innym niż ten, na którym został przygotowany, szkolenie personelu obsługującego program itd.): 10% Konserwacja programu: dalsze 100%... usługi gwarancyjne, inne błędy, usuwanie problemów związanych z nowym sprzętem itd. McCrackena i Salmon, 1987 Styl programowania Ogólne reguły: nazwy zmiennych w programie, wielkości stałe, liczba zmiennych globalnych, deklaracje typów zmiennych, odstępy, puste linie, akapity, inteligentne komentarze, podział na sekcje, podprogramy. McCracken, Salmon, 1987 Nazwy zmiennych w programie Zależnie od przeznaczenia: rzeczowniki dla oznaczania nazw wszelkich danych, czasowniki dla funkcji i procedur (rozkazy, np. dziel, dodaj itp), przymiotniki dla zmiennych logicznych. Mnemoniczne nazwy nazwy jednolite - mało czytelne l1, l2, l3, l55, l78, lepiej - nazwy, które coś oznaczają, 3
powiadamiają programistę o możliwościach modułu wskazują sens stałych, zmiennych, typów itd. Bardzo długie nazwy mało praktyczne, nieczytelne (dodajdwieliczby) stosować wyróżnienia! DodajDwieLiczby, dodaj_dwie_liczby. 18 19 20 Wielkości stałe Problemy: wielkości niecharakterystyczne stała pi, charakterystyczna zapisana z 9 miejscami zamienić na liczbę o 12 miejscach znaczących. rozmiar tablicy w programie (w modułach) [1..100]. automatyczna zamiana (edytor) 100 200, przy okazji, np. temperatura procesu 100 200? Oprócz 0, 1 i może jeszcze kilku innych nie używać wprost stałych w treści programu. zadeklarować (zgłosić) je w specjalnej części! Zalecenia Minimalizować liczbę zmiennych globalnych zmiana globalna, łatwa pomyłka Deklarować typy zmiennych (using) podzakresy, definicje tablic, rekordów, plików itp. Stosować odstępy, wcięcia puste linie (jedna, dwie) POWINNY! oddzielać różne fragmenty programu i podprogramy wcięcia w instrukcjach złożonych. zdecydować się na jakiś styl przestrzegać go (jednolita postać programu). Modularyzacja, komentarze Podział na moduły (podprogramy) podział zadania na części oprogramowanie i sprawdzenie części połączenie części (wg zasady dziel i rządź) spójność modułów jeśli uda się znaleźć słowo określające to co robi dany moduł, to oznacza, że funkcja jest spójna. przejrzystość komunikacji modułów Inteligentne komentarze x = 7; //pod zmienną x podstawiamy 7??? 21 Im większy program im większy zespół tym ważniejsze, by stosować ww. uwagi 22 23 Wprowadzenie do testologii 1. Testy modułowe analiza ścieżek (path analysis) użycie klas równoważności (equivalence partition) testowanie wartości brzegowych testowanie składniowe 2. Testy integracyjne pomiędzy: modułami: funkcjonalne modułami: wydajnościowe 3. Testy integracyjne pomiędzy: 4. systemami: funkcjonalne 5. systemami: wydajnościowe 6. systemami: regresywne Testy w praktyce (VS) Testy jednostkowe 4
sprawdzają funkcjonalność i poprawność, Testy bazy danych testy jednostkowe służące do testowania procedur składowanych i innych artefaktów bazodanowych, Testy web monitorowanie ruchu pomiędzy przeglądarką a serwerem WWW. 24 25 w praktyce Testy UI rejestrowane są operacje wykonywane przez użytkownika (kliknięcia, wprowadzenia określonych tekstów z klawiatury itp.); można je potem użyć np. do automatyzacji testów funkcjonalnych; Testy obciążeniowe symulujące olbrzymią liczbę użytkowników, którzy wykonują określone czynności. Podstawowe narzędzia testowania Śledzenie pracy programu: WriteLine, msgbox 26 27 28 29 30 31 Narzędzia środowiska Debug: śledzenie pracy programu praca krokowa Step Into, Step Over punkty zatrzymania breakpoint wykonanie instrukcji i modyfikacja Immediate Punkty kontrolne breakpoint Ustawienie F9 Wartości zmiennych Zatrzymanie okno Locals okno Immediate Praca krokowa Wartości zmiennych Locals Zaawansowane narzędzia VS Testy jednostkowe Testy bazy danych Testy web Testy UI Testy obciążeniowe http://msdn.microsoft.com/pl-pl/library/testowanie--wstep.aspx Testy jednostkowe Automatyczne testowanie aplikacji dla wybranych funkcji (metod) określić dane We/Wy wywołać funkcję, porównać komunikat o niezgodności. Programista/tester uruchamia wybrane/wszystkie testy otrzymuje informacje o niezgodnościach. 5
32 33 34 35 36 37 38 Testy jednostkowe w VS Można oczywiście utworzyć ręcznie VS dostępny kreator Generowanie testów Testy jako nowy projekt Wygenerowany test Dla metody Plus() [TestMethod()] public void PlusTest() { int numbera = 0; // TODO: Initialize to an appropriate value int numberb = 0; // TODO: Initialize to an appropriate value int expected = 0; // TODO: Initialize to an appropriate val int actual; actual = Program.Plus(numberA, numberb); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } Wyniki testu Uruchomienie kliknąć na nazwie testu z menu kontekstowego wybrać Run Tests komunikat z wynikami return numbera * numberb; Dalsze informacje Opis testów jednostkowych VS http://msdn.microsoft.com/pl-pl/library/testy-jednostkowe-w-visual-studio Ogólnie o testowaniu http://msdn.microsoft.com/pl-pl/library/hh150106(v=vs.100).aspx Z życia testera (za http://www.testowanie.net/testowanie/cykl-wytwarzania-oprogramowania/) Programista tworzy bezbłędny kod. Dział testów znajduje 20 błędów w aplikacji. Programista: poprawia 10 z nich; pozostałe to nie błędy Dział testów: odrzuca 5 z 10 poprawek i znajduje 15 nowych błędów. cykl poprawki/retesty powtarza się 3 razy Naciski działu marketingu/handlowego - produkt zostaje wypuszczony. Klient znajduje 137 błędów. Programista pobrał już wynagrodzenie z kontraktu i jest nieosiągalny. Nowy zespół programistów poprawia 137 błędów i wprowadza 456 nowych. Programista, który stworzył system, wysyła kartkę z Fidżi do niedofinansowanego działu testów. Dział testów odchodzi. Firma zostaje kupiona przez konkurencję za profity uzyskane ze sprzedaży ich ostatniej aplikacji, która zawiera 783 błędy. Nowy szef zatrudnia programistę, aby napisał ten sam program od podstaw. Programista tworzy bezbłędny kod 6