J.Nawrocki, M. Antczak, G. Palik Plik źródłowy: 07cw8-io.doc; Data: 2007/9/26 17:14:00 A9/P9 1. Diagramy przypadków użycia Ćwiczenie nr 8 Inżynieria Oprogramowania Wprowadzenie Pomiędzy przypadkami użycia mogą zachodzić następujące relacje: include oznacza, że dany przypadek użycia zawiera inny, extend oznacza, że dany przypadek użycia może być opcjonalnie wykonany w ramach innego. 2. Automatyzacja testów jednostkowych programów napisanych w języku C z wykorzystaniem narzędzia CUnit oraz generacja dokumentacji użytkowej na podstawie komentarzy zawartych w kodzie programu z wykorzystaniem narzędzia Doxygen. Naszym zadaniem jest napisanie prostego programu w języku C (kalkulator) realizującego proste funkcje dodawania i mnożenia liczb całkowitych oraz zaproponowanie i zaimplementowanie kilku przypadków testowych, wspomagających wykrywanie błędów w pisanym przez nas oprogramowaniu. W celu szybkiej konfiguracji środowiska uruchomieniowego należy pobrać pakiet CUnitPowerPack.zip, który zawiera środowisko programistyczne Dev-C++, bibliotekę CUnit, podręcznik wspomagający (krok po kroku) instalację i konfigurację powyższych narzędzi oraz projekt CUExample, który jest przykładową implementacją powyższego zadania i może być wykorzystywany w celu zrozumienia idei i implementacji testów jednostkowych. Przykładowy projekt CUExample, stworzony w środowisku Dev-C++, składa się z następujących plików: src/main.c #include "includes/calc.h" int main() int a,b; printf("define a:"); scanf("%d",&a); printf("define b:"); scanf("%d",&b); printf("\nadding result: %d",add(a,b)); printf("\nsubtracting result: %d",sub(a,b));
printf("\nmultiplying result: %d\n\n",mul(a,b)); system("pause"); return 0; src/calc/calc.c #include "../includes/calc.h" int add(int a, int b) return a+b; int sub(int a, int b) return a-b; int mul(int a, int b) return a*b; src/includes/calc.h /*! \file calc.h \brief Header file for calc module. #ifndef _CALC_H_ #define _CALC_H_ #include <stdio.h> #include <stdlib.h> /*! \fn int add(int a, int b); \brief Adding two values. \param a First value. \param b Second value. int add(int a, int b); /*! \fn int sub(int a, int b); \brief Subtracting two values. \param a First value. \param b Second value. int sub(int a, int b); /*! \fn int mul(int a, int b); \brief Multiplying two values. \param a First value. \param b Second value. int mul(int a, int b); #endif test/maintest.c #include <stdio.h> #include <string.h> #include "CUnit/Automated.h" #include "../src/includes/calc.h"
/* The suite initialization function. * Returns zero on success, non-zero otherwise. int init_suite(void) return 0; /* The suite cleanup function. * Returns zero on success, non-zero otherwise. int clean_suite(void) return 0; void test_calc_add_true(void) CU_ASSERT(3 == add(1,2)); void test_calc_add_false(void) CU_ASSERT(4!= add(1,2)); void test_calc_sub_true(void) CU_ASSERT(-1 == sub(1,2)); void test_calc_sub_false(void) CU_ASSERT(2!= sub(1,2)); void test_calc_mul_true(void) CU_ASSERT(2 == mul(1,2)); void test_calc_mul_false(void) CU_ASSERT(3!= mul(1,2)); /* The main() function for setting up and running the tests. * Returns a CUE_SUCCESS on successful running, another * CUnit error code on failure. int main() CU_pSuite pcalcsuite = NULL; /* initialize the CUnit test registry if (CUE_SUCCESS!= CU_initialize_registry()) return CU_get_error();
/* add a suite to the registry pcalcsuite = CU_add_suite("calc_suite", init_suite, clean_suite); if (NULL == pcalcsuite) CU_cleanup_registry(); return CU_get_error(); /* add the tests to the suite if ((NULL == CU_add_test(pCalcSuite, "calc_add_true", test_calc_add_true)) (NULL == CU_add_test(pCalcSuite, "calc_add_false", test_calc_add_false)) (NULL == CU_add_test(pCalcSuite, "calc_sub_true", test_calc_sub_true)) (NULL == CU_add_test(pCalcSuite, "calc_sub_false", test_calc_sub_false)) (NULL == CU_add_test(pCalcSuite, "calc_mul_true", test_calc_mul_true)) (NULL == CU_add_test(pCalcSuite, "calc_mul_false", test_calc_mul_false))) CU_cleanup_registry(); return CU_get_error(); /* Run all tests using the CUnit Automated interface CU_set_output_filename("CUExampleTests"); CU_list_tests_to_file(); CU_automated_run_tests(); CU_cleanup_registry(); return CU_get_error(); Zadania Zad. 1. Uzupełnij. Inżynieria oprogramowania jest to zastosowanie.,, podejścia do oprogramowania. Zad. 2. Uzupełnij. W ramach inżynierii oprogramowania wyróżniamy 8 obligatoryjnych jednostek wiedzy: a) ustalenie co budowany system ma robić, b).. zaproponowanie struktury rozwiązania, c) - utrzymania użyteczności programu i umiejętnego wprowadzania do niego koniecznych zmian, d) uwzględniają różne modele cyklu życia oprogramowania, które wpływają na planowanie przedsięwzięć programistycznych, e).. harmonogramowanie, śledzenie postępów, raportowanie, w razie problemów lub modyfikacji proponowanie i wdrażanie czynności naprawczych, f)... Zad. 3. Uzupełnij. W ramach inżynierii oprogramowania wyróżniamy 4 opcjonalne jednostki wiedzy: a), b), c),
d). Zad. 4. Uzupełnij. W ogólności cykl życia przedsięwzięcia programistycznego składa się z następujących faz: a), b) (wykorzystanie języka ), c), d). Zad. 5. Uzupełnij. Proces zbierania i opracowywania wymagań: a) ma charakter, b) poprzedzony jest, c) składa się z następujących trzech faz: faza musi uwzględniać, że wymagania często pochodzą od wielu różnych osób i na dodatek należy uwzględniać ograniczenia wynikające np.: z różnych przepisów prawa, celem tej fazy jest wczesne (najmniej kosztowne) wykrywanie sprzeczności i wzajemnej niejednoznaczności współistniejących wymagań projektowanego systemu, w celu usunięcia zauważonych w powyższej fazie sprzeczności między wymaganiami należy przeprowadzić negocjacje z wieloma zainteresowanymi osobami osiągnięcie kompromisu często jest trudnym problemem. Zad. 6. Uzupełnij. Wyróżniamy dwa podstawowe rodzaje wymagań: a) - opisują funkcje, jakie ma realizować system, b) - dotyczą takich aspektów, jak wydajność (np.: szybkość wykonania poszczególnych operacji), czy niezawodność. Zad. 7. Skompletuj specyfikację wymagań do obsługi internetowej księgarni korzystając z poniższych opowieści klienta: a) po złożeniu zamówienia przez klienta, dział zamówień pobiera książki z magazynu i przekazuje je do działu wysyłek, zajmującego się przygotowaniem paczki i wysłaniem pod wskazany adres. b) klient wybiera książki, a księgarnia informuje o ich cenie (po otrzymaniu informacji o wartości zamówienia klient może zrezygnować z pewnych książek lub z całego zamówienia). Księgarnia ustala z klientem adres, pod który zamówienie ma zostać wysłane, jak również sposób zapłaty. Jeżeli wybrano zapłatę kartą kredytową, a transakcja zapłaty się nie powiodła, to należy ponownie ustalić sposób zapłaty. Klient może zrezygnować z zakupów, jeżeli zapłata kartą kredytową będzie niemożliwa.
c) (*) dział zamówień, po otrzymaniu zamówienia od klienta, przekazuje listę książek do magazynu. Jeżeli wszystkie książki są dostępne w magazynie, są one od razu zwracane do działu zamówień. Jeśli natomiast jakiejś pozycji brakuje, prowadzący magazyn odpowiedzialny za zamówienie danego egzemplarza u wydawcy. W takiej sytuacji magazyn informuje dział zamówień, o braku wszystkich książek, wraz z szacowanym terminem ich sprowadzenia. Może się również zdarzyć, że pewnych książek nie można już kupić (np.: nakład się wyczerpał), magazyn informuje wtedy dział zamówień o braku możliwości zrealizowania zamówienia. Magazyn jest również zobowiązany do sprawdzenia jakości książek otrzymanych z wydawnictwa: czy są wszystkie strony, czy okładka ani strony nie są pogniecione, itp. d) (*) księgarnia informuje o możliwościach dokonania zapłaty: przelewem, za pobraniem lub płatność kartą kredytową. Jeżeli klient wybierze płatność przelewem, jest informowany o numerze konta bankowego, wraz z dokładną sumą jaką należy wpłacić. Opcja za pobraniem nie wymaga dodatkowych kroków, natomiast w przypadku wybrania karty kredytowej, system próbuje wykonać transakcję na karcie (pobiera od klienta numery karty i hasło CVV, następnie kontaktuje się z Centrum Obsługi i dokonuje transakcji). Klient jest informowany, w przypadku wystąpienia błędu podczas tej operacji. Zad. 8. (*) Skompletuj specyfikację wymagań do obsługi bankomatu korzystając z poniższych opowieści klienta: a) przed rozpoczęciem korzystania z bankomatu klient musi zostać zautoryzowany. Następnie bankomat prezentuje klientowi możliwe opcje (tylko jeżeli autoryzacja się powiodła). Klient może podjąć decyzję o pobraniu gotówki lub sprawdzeniu salda. W przypadku sprawdzenia salda bankomat prezentuje stan konta. Po potwierdzeniu odczytania salda bankomat ponownie prezentuje klientowi dostępne opcje. b) autoryzacja klienta rozpoczyna się od wprowadzenia przez klienta karty do bankomatu. Bankomat prosi klienta o podanie PIN. Po podaniu PIN przez klienta bankomat sprawdza jego poprawność. Jeżeli PIN jest niepoprawny, to bankomat prosi klienta o ponowne podanie PIN. Jeżeli klient poda niepoprawny PIN trzy razy, to bankomat informuje klienta o zatrzymaniu karty, a autoryzacja kończy się niepowodzeniem. c) bankomat prezentuje klientowi domyślne kwoty do wypłacenia. Klient wybiera jedną z nich (opcjonalnie klient może sam określić kwotę do wypłaty). Następnie bankomat sprawdza, czy klient posiada wystarczającą ilość środków na koncie. Jeżeli wybrana przez klienta kwota przekracza saldo rachunku, to bankomat informuje klienta o stanie konta i prosi o wybranie innej kwoty. Jeżeli wybrana przez klienta kwota nie przekracza stanu rachunku to bankomat wydaje klientowi kartę i pieniądze. Zad. 9. Uzupełnij. obejmuje wiele różnego typu diagramów, które pozwalają w sposób graficzny. Na wykładzie przedstawione zostały bardzo proste przykłady (modelowanie możliwych stanów projektowanego systemu), (modelowanie wymagań funkcjonalnych) i (ilustrowanie komunikacji między obiektami). Zad. 10. Uzupełnij specyfikację wymagań z zadania 7 o następujące diagramy: a) Diagram przypadków użycia b) Diagram sekwencji dla UC1 c) (*) Diagram sekwencji dla UC2 d) (*) Diagram sekwencji dla UC3 e) (*) Diagram sekwencji dla UC4 Zad. 11.(*) Uzupełnij specyfikację wymagań z zadania 2 o następujące diagramy: a) Diagram przypadków użycia b) Diagram sekwencji dla UC1
c) Diagram sekwencji dla UC2 d) Diagram sekwencji dla UC3 Zad. 12. Uzupełnij. jest bezpośrednio związana jednostką wiedzy dotyczącą walidacji. W trakcie pracy nad systemem informatycznym powstaje cały szereg różnego typu artefaktów:. Oczywiście, muszą to być produkty dobrej jakości. Zad. 13. Zaznacz poprawne odpowiedzi. W cyklu życia procesu zbierania wymagań kontrola jakości artefaktów jest wykonywana: a) w ostatniej fazie pracy nad artefaktem, b) wielokrotnie będąc istotnym elementem fazy analizy wymagań. Zad. 14. Uzupełnij. Wyróżniamy dwie podstawowe postaci kontroli jakości: a) - można wykonywać tylko w odniesieniu do działającego systemu lub jego prototypu, b) - można je stosować zarówno do kodu, jak i do specyfikacji wymagań, gdyż ich istotą jest analiza artefaktów. Analiza ta może być przeprowadzona przez pojedynczą osobę (nazywamy to recenzją) lub też przez zespół osób (najpopularniejszym przykładem są inspekcje). Zad. 15. Uzupełnij. (np.: dobrze znane już sieci Petriego) mają ścisły związek z walidacją oprogramowania. Poprawność programów wykazywana jest na gruncie matematycznym, poprzez. Zad. 16. Uzupełnij. W celu dowodzenia poprawności funkcjonalnej określonej funkcji zapisanej w dowolnym języku programowania np.: C należy: a) związać z tą funkcją (precondition określa relację jakie muszą spełniać parametry wejściowe, aby mogło wystąpić poprawne wykonanie funkcji np.: /*** PRE **) i (postcondition określa relację, jaka ma być prawdziwa na końcu wykonania podprogramu np.: /*** POST **), b) dowieść, że jeżeli warunek wstępny jest spełniony to po wykonaniu mechanizmów zapisanych w podprogramie osiągniemy warunek końcowy. Dowodzenie poprawności programu zawierających pętle odbywa się (ang. invariant ). jest to zdanie, które jest prawdziwe za każdym razem, kiedy powtarzane jest wykonanie instrukcji zawartych w pętli. Dokładnie mówiąc, zdanie spełniające powyższą zależność powinno być prawdziwe tuż przed pierwszym wykonaniem instrukcji zawartych w pętli, tuż przed drugim wykonaniem, przed trzecim itd. Zasadniczy problem polega na tym by znaleźć (wymyślić) takie zdanie, który zawsze będzie prawdzie i jednocześnie pomoże nam w udowodnieniu warunku końcowego POST. Powyższa metoda składa się z następujących etapów:
poprawności odpowiednich niezmienników, w oparciu o zdefiniowane powyżej niezmienniki. Zad. 17. Udowodnij poprawność funkcji wyznaczającej n-ty wyraz ciągu Fibonacciego wykorzystując metodę niezmienników zaprezentowaną na wykładzie. Ciąg Fibonacciego jest zdefiniowany w następujący sposób: Badany program w języku C ma następującą postać: int Fib(int n) int k, f0, f1, f2; k = 0; f0 = 1; f1 = 1; while (k!= n) k = k + 1; f2 = f0 + f1; f0 = f1; f1 = f2; ; return f0; ; Zad. 18(*) Udowodnij poprawność funkcji wyznaczającej wartość funkcji potęgowej a b dla a, b będących liczbami naturalnymi (0,1, 2,..) wykorzystując metodę niezmienników. Badany program w języku C ma następującą postać: Badany program w języku C ma następującą postać: int Pow(int a, int b) int result, k; k = 0; result = 1; while (k <= b) k = k + 1; result = result * a; ; return result; ; Zad. 19. Uzupełnij. Formalna specyfikacja programów może być i jej jest zadaniem samym w sobie. Zad. 20. Uzupełnij. są praktycznie nie do uniknięcia. Właściwe jest podstawą skutecznej ewolucji oprogramowania i jedną z kluczowych praktyk. Zad. 21. Uzupełnij. Formalne podejście do zarządzania zmianami zostało zaprezentowane na poniższym rysunku.
Zad. 22. Uzupełnij. (np.: CVS, SubVersion), chronią oprogramowanie przed chaotycznymi modyfikacjami i umożliwiają współbieżne modyfikowanie różnych składników oprogramowania w sposób kontrolowany. Zad. 23. Uzupełnij. Testowanie oprogramowania: a) ma ścisły związek z, a także z oprogramowania i dostarcza danych, które mogą być wykorzystane do określenia, b) jest to dla kombinacji w celu. Im więcej błędów zostanie wykrytych tym jest, ale też tym gorzej to świadczy o. Pracochłonność testowania waha się od całkowitej pracochłonności w ogólnym przypadku do 70%-80% całkowitej pracochłonności w przypadku. Zad. 24. Uzupełnij. Wykonanie przypadku testowego można opisać przy pomocy następujących kroków: a) testowany system bądź jego fragment są ustawiane w stanie, b) podawane są do testowanej implementacji i wyroczni ( najczęściej wyjścia ustalane są przez ), c) jest porównywane z w celu ustalenia czy test ujawnił błąd. Zad. 25. Uzupełnij. opisywana jest jako prawdopodobieństwo znalezienia jeszcze nie wykrytego błędu. Zad. 26(*). Korzystając z przykładu umieszczonego we wprowadzeniu i przeanalizowanego na ćwiczeniach stwórz projekt, który będzie zawierał program (napisany w języku C patrz programowanie imperatywne) rozwiązujący równanie kwadratowe ax 2 + bx + c = 0 (uwzględnij wszystkie możliwe przypadki wartości współczynników a, b, c) oraz kilka (np.:3) krytycznych przypadków testowych.
Zad. 27. Uzupełnij. to taki, który wykrywa jeszcze nie wykryty błąd. Zad. 28. Uzupełnij. (extreme Programming) jest to zestaw praktyk dotyczących m.in. specyfikacji wymagań, weryfikacji i walidacji, ewolucji kodu, różnych procesów związanych z rozwojem oprogramowania a także z zarządzaniem przedsięwzięciem programistycznym. Zad. 29. Uzupełnij. Podstawowe zagrożenia związane z komercyjnym wytwarzaniem oprogramowania to: a) przekraczanie założonych i skojarzonych z przedsięwzięciem, b) programiści pracują w, c) jakość powstającego oprogramowania jest i użytkowników końcowych. Zad. 30. Uzupełnij. Główną przyczyną powyższych problemów jest w procesie wytwarzania i pielęgnacji projektu programistycznego. Pierwsza próba rozwiązania kryzysu polegała na i w celu zwalczenia kryzysu oprogramowania, ale. Następnie wprowadzono, które były bardziej zorientowane na niż kurczowe trzymanie się planu (np.: XP). Zad. 31. Uzupełnij. W programowaniu ekstremalnym: a), b) artefakty, które muszą powstawać zostały ograniczone do, c) programiści nie muszą pracować w, d) występują pewne, które muszą być stosowane, aby przedsięwzięcie zakończyło się.