Τμήμα Πληροφορικής Πανεπιστήμιο Κύπρου ΕΠΛ132 Αρχές Προγραμματισμού II Διάλεξη 17: Έλεγχος Λογισμικού (Κεφάλαιο 24.1-24.2, KNK-2ED) Δημήτρης Ζεϊναλιπούρ http://www.cs.ucy.ac.cy/courses/epl132 17-1
Μεγάλης Κλίμακας Λογισμικό (Κύκλος Ανάπτυξης) Ο Κύκλος Ανάπτυξης ενός λογισμικού & Παραλληλισμός Εκτός ΕΠΛ132 Ανάλυση / Analysis Π.χ., Εκφώνηση Εργασίας με αυτά που μάθαμε στο EΠΛ132. Διάλεξη 17 Σχεδιασμός / Design Δημιουργία Δομής Προγράμματος Code Design (μέσω δημιουργίας αρχείων κεφαλίδας) Model-Driven- Design (μέσω εργαλείου τύπου Rhapsody) Όλο το ΕΠΛ132 Υλοποίηση / Implementation Υλοποίηση Συναρτήσεων (ατομικά ή ομαδικά) Διάλεξη 18 Έλεγχος & Δοκιμή / Testing Υλοποίηση Οδηγών Δοκιμής (ανά module / συνολικά) Βασικό Αντικείμενο Μελέτης του μαθήματος Τεχνολογίας Λογισμικού Εκτός ΕΠΛ132 Λειτουργία / Συντήρηση Υπεύθυνος Εργαστηρίου (εκτός Συντήρησης) 17-2
Περιεχόμενο Διάλεξης 18 Εισαγωγή στον Έλεγχο Λογισμικού Προγραμματιστές vs. Δοκιμαστές Έλεγχοι Μονάδων (Unit Testing) Ορισμοί, Κάλυψη Μονοπατιών Προγράμματος (code coverage) Έλεγχοι ΧΩΡΙΣ Εργαλεία: Συγγραφή Οδηγών (Drivers) και Επιβεβαίωση Ισχυρισμών assert() Έλεγχοι ΜΕ Εργαλεία: CUnit (C), Junit (JAVA) Ανάλυση Κώδικα: Θέματα Επίδοσης Έννοιες: Στατική & Δυναμική Ανάλυση Κώδικα Εργαλεία: Valgrind, gprof, JProfiler (JAVA) και διασύνδεση με Eclipse 17-3
Έλεγχος Λογισμικού (Software Testing) Η Έλεγχος Λογισμικού (Software Testing) αφόρα τη ενδελεχή επικύρωση ότι το λογισμικό ανταποκρίνεται στις απαιτήσεις των σχεδιαστών και κατ' επέκταση χρηστών. Πολύ μεγάλο θέμα από μόνο του! Μελετάται σε περισσότερο βάθος σε μαθήματα Τεχνολογίας Λογισμικού Πολλές εταιρείες αφιερώνουν περισσότερο από 50% του χρόνου τους στον έλεγχο, π.χ., Επαγγελματικές Κατευθύνσεις Microsoft Software Engineering: Build Software Engineering: Test Software Engineering: User Experience 17-4
Έλεγχος Λογισμικού (Software Testing) Προγραμματιστής (Programmer) Δοκιμαστής (Tester) Αναπτύσσει & βλέπει τον πηγαίο κώδικα Αποσφαλματώνει Επικυρώνει την ορθότητα των μονάδων και βιβλιοθηκών. Δεν Βλέπει τον κώδικα. Επικυρώνει ότι το πρόγραμμα (συνολικά) ανταποκρίνεται στις απαιτήσεις. White-box Tester Θέμα Διάλεξης!!! Black-box Tester (περισσότερα στη Τεχνολογία Λογισμικού) 17-5
Περιεχόμενο Διάλεξης 18 Εισαγωγή στον Έλεγχο Λογισμικού Προγραμματιστές vs. Δοκιμαστές Έλεγχοι Μονάδων (Unit Testing) Ορισμοί, Κάλυψη Μονοπατιών Προγράμματος (code coverage) Έλεγχοι ΧΩΡΙΣ Εργαλεία: Συγγραφή Οδηγών (Drivers) και Επιβεβαίωση Ισχυρισμών assert() Έλεγχοι ΜΕ Εργαλεία: CUnit (C), Junit (JAVA) Ανάλυση Κώδικα: Θέματα Επίδοσης Έννοιες: Στατική & Δυναμική Ανάλυση Κώδικα Εργαλεία: Valgrind, gprof, JProfiler (JAVA) και διασύνδεση με Eclipse 17-6
Έλεγχοι Μονάδας (Unit Testing) Έλεγχος Μονάδας: Είδος White-box Testing για "χαμηλού επιπέδου" δοκιμή ενός λογισμικού. Γίνεται από τον Προγραμματιστή (όχι τον Δοκιμαστή) Από τη διάλεξη 12, ήδη κάνουμε ένα είδος unit testing, με τη χρήση των οδηγών ελέγχου (drivers) οι οποίοι περιλαμβάνονταν κατά το DEBUG. Εδώ θα δούμε την πιο επαγγελματική έκδοση των οδηγών αυτών (γνωστά ως unit test frameworks) Οι δοκιμές γίνονται πάνω σε συγκεκριμένες μονάδες (modules) ή βιβλιοθήκες (libraries) Command < Function < Module < Library < Software Απαιτεί γνώση της εσωτερικής σχεδίασης και του EPL132: πηγαίου Programming κώδικα. Principles II - Demetris Zeinalipour (University of Cyprus) 17-7
Κάλυψη Μονοπατιών σε Ελέγχους O Έλεγχος Μονάδας περιλαμβάνει τον έλεγχο ΟΛΩΝ των μονοπατιών της μονάδας. Απλό σε περιπτώσεις όπου ΔΕΝ υπάρχουν επαναλήψεις, εφόσον ο αριθμός το "μονοπατιών" της μονάδας είναι μικρός. if ( ) { } else { } Όταν υπάρχουν επαναλήψεις, ο αριθμός των μονοπατιών αυξάνεται εκθετικά: while (i<1000) { } Μονάδας (Code Coverage) if ( ) { } else { } 2 μονοπάτια! 2 1000 μονοπάτια! 17-8
Κάλυψη Μονοπατιών σε Ελέγχους int i = 0; Μονάδας (Code Coverage) do { i++; if ( ) { if ( ) { if ( ) { } else { } } else { if ( ) { } else { } } } else { } true if() if() if() i++; if() false while(i<20) Μονοπάτια/loop: 5 Επαναλήψεις: 20 Σύνολο Μονοπατιών: = 5 20 = 95 x 10 12 (Τρισεκατομμύρ ια μονοπάτια!) } while (i<20); Source Code Control Flow Graph Πηγή: The Art of Software Testing, Myers', 3 rd Edition, 2011 17-9
Έλεγχοι Μονάδας (Unit Testing) Γίνεται Πότε; Όταν υλοποιηθούν οι μονάδες (modules) του προγράμματος (στη C) ή αντίστοιχα κλάσεις (στη JAVA) Στο Extreme Programming οι έλεγχοι γράφονται ακόμη και πριν την ανάπτυξη της μονάδας! Πλεονέκτημα: Εύκολη επικύρωση της ορθότητας μια μονάδας σε περιπτώσεις αλλαγών ή εντοπισμό σφαλμάτων (γνωστό ως regression testing) Προσοχή: Ο Έλεγχος Μονάδας αναδεικνύει μόνο τα λάθη, ΔΕΝ αναδεικνύει ότι ένα πρόγραμμα είναι ορθό. Ωστόσο, αναδεικνύεται ότι μια μονάδα καλύπτει τις περιπτώσεις για τις οποίες σχεδιάστηκε. 17-10
Χωρίς Εργαλεία: Χειρονακτική Γραφή Οδηγών Δοκιμής όπως κάνουμε από τη Διάλεξη 12. Λαμβάνουμε πλέον υπόψη όλα τα μονοπάτια εκτέλεσης (Code Coverage τεχνικές) που είδαμε στη προηγούμενη διαφάνεια. Χρήση Επιβεβαίωσης Ισχυρισμών (Assertions) Με Εργαλεία Έλεγχοι Μονάδας (Μεθοδολογία) Εργαλεία Συγγραφής Ελέγχων Μονάδων Είσοδος: Πηγαίος Κώδικας, Πλάνο Ελέγχων. Έξοδος: Αναφορά Ελέγχων (Unit Test Report) Στατική & Δυναμική Ανάλυση Κώδικα (Θέματα Επίδοσης) 17-11
#ifdef DEBUG /* Από Διάλεξη 12 */ /* Declaring Object Unit Tests */ static void tester1() {... } static void tester2() {... } int main(void) { } #endif tester1(); tester2(); //... return 0; Έλεγχοι Μονάδας ΧΩΡΙΣ Εργαλεία Μειονεκτήματα - Όχι Ιδιαίτερη Σημασιολογία στο τι επιτυγχάνει και τι όχι. - Θα ήταν καλύτερα να παίρναμε μια αναφορά (report) που να συνόψιζε τι πέτυχε και τι όχι. - Θα δούμε σε λίγο πως βελτιώνεται αυτό (CUnit) 17-12
Έλεγχοι Μονάδας ΧΩΡΙΣ Εργαλεία (Assertions) Μια εναλλακτική (ή συμπληρωματική) πρακτική για τον έλεγχο μονάδων είναι αυτή της Επιβεβαίωσης Ισχυρισμών (Assertions) Υποστηρίζεται από όλες τις δημοφιλής γλώσσες! Παράδειγμα #include <assert.h> // assert() #include <stdlib.h> // EXIT_SUCCESS int main() { int A[10], i = 15; assert(0<=i && i<10); A[i] = 0; return EXIT_SUCCESS; } Εκτέλεση Το assert λοιπόν μπορεί να το φανταστεί κανείς ως μια συνθήκη ελέγχου if, η οποία τερματίζει τη ροή εκτέλεσης ενός προγράμματος εάν δεν ικανοποιείται η συνθήκη. Assertion failed: (0<=i && i<10), function main, file new.c, line 6. Abort trap 17-13
Έλεγχοι Μονάδας ΧΩΡΙΣ Εργαλεία (Assertions) Μειονέκτημα assert: Ο Χρόνος εκτέλεσης του προγράμματος αυξάνεται από τον επιπλέον έλεγχο, assert (condition). Συνεπώς, πολλοί χρησιμοποιούν το assert μόνο κατά την φάση της δοκιμής / αποσφαλμάτωσης με την ακόλουθη λογική: Εισαγωγή της assert.h αφού πρώτα γίνει def το NDEBUG. #define NDEBUG #include <assert.h> Στην περίπτωση μας θα μπορούσαμε να συνδυάσουμε με τη DEBUG μεταβλητή του makefile μας. #ifdef DEBUG #define NDEBUG #include <assert.h> #endif 17-14
Έλεγχοι Μονάδας ΜΕ Εργαλεία (Το Εργαλείο CUnit) Χρήση CUnit για τον έλεγχο μονάδων μιας μοναδας C 17-15
Έλεγχοι Μονάδας ΜΕ Εργαλεία (Το Εργαλείο CUnit) /* Simple test of fprintf(). * Writes test data to the temporary file and checks * whether the expected number of bytes were written. */ void testfprintf(void) { int i1 = 10; } if (NULL!= temp_file) { CU_ASSERT(0 == fprintf(temp_file, "")); CU_ASSERT(2 == fprintf(temp_file, "Q\n")); CU_ASSERT(7 == fprintf(temp_file, "i1 = %d", i1)); } Παράδειγμα CUnit Test (Test Driver γραμμένο σε CUnit) /* 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 psuite = NULL; psuite = CU_add_suite("Suite_1", init_suite1, clean_suite1); CU_add_test(pSuite, "test of fprintf()", testfprintf);... CU_basic_run_tests(); return CU_get_error(); } Συναρτήσεις αρχικοποίησης ελέγχων 17-16
Έλεγχοι Μονάδας ΜΕ Εργαλεία (Το Εργαλείο JUnit) Χρήση JUnit για τον έλεγχο μονάδας κλάσεων JAVA 17-17
Περιεχόμενο Διάλεξης 18 Εισαγωγή στον Έλεγχο Λογισμικού Προγραμματιστές vs. Δοκιμαστές Έλεγχοι Μονάδων (Unit Testing) Ορισμοί, Κάλυψη Μονοπατιών Προγράμματος (code coverage) Έλεγχοι ΧΩΡΙΣ Εργαλεία: Συγγραφή Οδηγών (Drivers) και Επιβεβαίωση Ισχυρισμών assert() Έλεγχοι ΜΕ Εργαλεία: CUnit (C), Junit (JAVA) Ανάλυση Κώδικα: Θέματα Επίδοσης Έννοιες: Στατική & Δυναμική Ανάλυση Κώδικα Εργαλεία: Valgrind, gprof, JProfiler (JAVA) και διασύνδεση με Eclipse 17-18
Στατική Ανάλυση Κώδικα (Static Code Analysis) Στατική Ανάλυση Κώδικα (Static Code Analysis): Η ανάλυση ενός κώδικα ΧΩΡΙΣ να εκτελεστεί (δηλ., σε επίπεδο πηγαίου κώδικα ή αντικειμενικού κώδικα) Μέρος τέτοιας ανάλυσης γίνεται σήμερα από τον μεταγλωττιστή, π.χ., unreachable code, variable-notused, κτλ. (παλαιότερο από άλλα εργαλεία, π.χ, lint) Σε αρκετά πεδία απαιτούνται σήμερα τυπικές μέθοδοι (formal methods) οι οποίες αποδεικνύουν με μαθηματικό τρόπο ότι ένα λογισμικό ανταποκρίνεται στις απαιτήσεις. (π.χ., λογισμικό για ιατρικούς ή πυρηνικούς σκοπούς) 17-19
Δυναμική Ανάλυση Κώδικα (Dynamic Code Analysis) Δυναμική Ανάλυση Κώδικα (Dynamic Code Analysis): Η ανάλυση ενός κώδικα MEΣΩ εκτέλεσης του προγράμματος σε ένα πραγματικό ή νοητό επεξεργαστή Κατά την εκτέλεση καταγράφονται στοιχεία για το πρόγραμμα (π.χ., χρήση μνήμης, επεξεργαστή, κτλ) Το αποτέλεσμα αυτής της ανάλυσης επιτρέπει στον χρήστη να εντοπίσει: Διαρροή Μνήμης (Memory Leaks) Χρόνος Συναρτήσεων, Απαίτηση Πόρων, κτλ. 17-20
Δυναμική Ανάλυση Κώδικα (Dynamic Code Analysis) Χρόνος Συναρτήσεων με gprof (βλέπε Εργαστήριο) gcc prog.c -pg -o prog; 80% του χρόνου! gprof bc prog 11.6 seconds* * Οι χρόνοι καταγράφονται κάνοντας sampling το πρόγραμμα 17-21
Δυναμική Ανάλυση Κώδικα (Dynamic Code Analysis) Εντοπισμός Διαρροών Μνήμης (Memory Leaks) με valgrind (βλέπε Εργαστήριο) valgrind --tool=memcheck --leak-check=full --show-reachable=yes --numcallers=20 --track-fds=yes./test * Εκτέλεση σε νοητό επεξεργαστή 17-22
Ανάλυση Κώδικα στο Eclipse (To linuxtools plugin) Κάνοντας install τα "linuxtools" στο Eclipse CDT μας δίνει την ευκαιρία χρήση του GProf, Valgrind και άλλων εργαλείων απευθείας από το eclipse CDT. 17-23
Ανάλυση Κώδικα στη JAVA με JProfiler To αντίστοιχο εργαλείο JProfiler για δυναμική ανάλυση προγραμμάτ ων JAVA 17-24