Τµήµα Πληροφορικής Πανεπιστήµιο Κύπρου ΕΠΛ132 Αρχές Προγραµµατισµού II Διάλεξη 17: Έλεγχος Λογισµικού (Κεφάλαιο 24.1-24.2, KNK-2ED) Δηµήτρης Ζεϊναλιπούρ http://www.cs.ucy.ac.cy/courses/epl132 17-1 Μεγάλης Κλίµακας Λογισµικό (Κύκλος Ανάπτυξης) Ο Κύκλος Ανάπτυξης ενός λογισµικού & Παραλληλισµός µε Εκτός ΕΠΛ132 Ανάλυση / Analysis Π.χ., Εκφώνηση Εργασίας Διάλεξη 17 Σχεδιασµός / Design Δηµιουργία Δοµής Προγράµµατος αυτά που µάθαµε στο EΠΛ132. Όλο το ΕΠΛ132 Υλοποίηση / Implementation Διάλεξη 18 Έλεγχος & Δοκιµή / Testing Βασικό Αντικείµενο Μελέτης του µαθήµατος Τεχνολογίας Λογισµικού Code Design Εκτός ΕΠΛ132 Υλοποίηση (µέσω δηµιουργίας Συναρτήσεων αρχείων κεφαλίδας) Λειτουργία / (ατοµικά ή Συντήρηση οµαδικά) Model-Driven- Υλοποίηση Design (µέσω Οδηγών Δοκιµής Υπεύθυνος εργαλείου τύπου (ανά module / Εργαστηρίου Rhapsody) συνολικά) (εκτός Συντήρησης) 17-2 1
Περιεχόµενο Διάλεξης 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 2
Έλεγχος Λογισµικού (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 3
Έλεγχοι Μονάδας (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 Κάλυψη Μονοπατιών σε Ελέγχους Μονάδας (Code Coverage) O Έλεγχος Μονάδας περιλαµβάνει τον έλεγχο ΟΛΩΝ των µονοπατιών της µονάδας. Απλό σε περιπτώσεις όπου ΔΕΝ υπάρχουν επαναλήψεις, εφόσον ο αριθµός το "µονοπατιών" της µονάδας είναι µικρός. if ( ) { J 2 µονοπάτια! else { Όταν υπάρχουν επαναλήψεις, ο αριθµός των µονοπατιών αυξάνεται εκθετικά: while (i<1000) { if ( ) { else { L 2 1000 µονοπάτια! 17-8 4
Κάλυψη Μονοπατιών σε Ελέγχους Μονάδας (Code Coverage) int i = 0; 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 Πηγή: EPL132: The Art Programming of Software Principles Testing, II Myers', - Demetris 3 rd Zeinalipour Edition, 2011 (University of Cyprus) 17-9 Έλεγχοι Μονάδας (Unit Testing) Γίνεται Πότε; Όταν υλοποιηθούν οι µονάδες (modules) του προγράµµατος (στη C) ή αντίστοιχα κλάσεις (στη JAVA) Στο Extreme Programming οι έλεγχοι γράφονται ακόµη και πριν την ανάπτυξη της µονάδας! Πλεονέκτηµα: Εύκολη επικύρωση της ορθότητας µια µονάδας σε περιπτώσεις αλλαγών ή εντοπισµό σφαλµάτων (γνωστό ως regression testing) Προσοχή: Ο Έλεγχος Μονάδας αναδεικνύει µόνο τα λάθη, ΔΕΝ αναδεικνύει ότι ένα πρόγραµµα είναι ορθό. Ωστόσο, αναδεικνύεται ότι µια µονάδα καλύπτει τις περιπτώσεις για τις οποίες σχεδιάστηκε. 17-10 5
Έλεγχοι Μονάδας (Μεθοδολογία) Χωρίς Εργαλεία: Χειρονακτική Γραφή Οδηγών Δοκιµής όπως κάνουµε από τη Διάλεξη 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) { tester1(); tester2(); //... return 0; #endif Έλεγχοι Μονάδας ΧΩΡΙΣ Εργαλεία Μειονεκτήµατα - Όχι Ιδιαίτερη Σηµασιολογία στο τι επιτυγχάνει και τι όχι. - Θα ήταν καλύτερα να παίρναµε µια αναφορά (report) που να συνόψιζε τι πέτυχε και τι όχι. - Θα δούµε σε λίγο πως βελτιώνεται αυτό (CUnit) 17-12 6
Έλεγχοι Μονάδας ΧΩΡΙΣ Εργαλεία (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> EPL132: #endif Programming Principles II - Demetris Zeinalipour (University of Cyprus) 17-14 7
Έλεγχοι Μονάδας ΜΕ Εργαλεία (Το Εργαλείο 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 8
Έλεγχοι Μονάδας ΜΕ Εργαλεία (Το Εργαλείο JUnit) Χρήση JUnit για τον έλεγχο µονάδας κλάσεων JAVA 17-17 Περιεχόµενο Διάλεξης 18 Εισαγωγή στον Έλεγχο Λογισµικού Προγραµµατιστές vs. Δοκιµαστές Έλεγχοι Μονάδων (Unit Testing) Ορισµοί, Κάλυψη Μονοπατιών Προγράµµατος (code coverage) Έλεγχοι ΧΩΡΙΣ Εργαλεία: Συγγραφή Οδηγών (Drivers) και Επιβεβαίωση Ισχυρισµών assert() Έλεγχοι ΜΕ Εργαλεία: CUnit (C), Junit (JAVA) Ανάλυση Κώδικα: Θέµατα Επίδοσης Έννοιες: Στατική & Δυναµική Ανάλυση Κώδικα Εργαλεία: Valgrind, gprof, JProfiler (JAVA) και διασύνδεση µε Eclipse 17-18 9
Στατική Ανάλυση Κώδικα (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 10
Δυναµική Ανάλυση Κώδικα (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 11
Ανάλυση Κώδικα στο Eclipse (To linuxtools plugin) Κάνοντας install τα "linuxtools" στο Eclipse CDT µας δίνει την ευκαιρία χρήση του GProf, Valgrind και άλλων εργαλείων απευθείας από το eclipse CDT. 17-23 Ανάλυση Κώδικα στη JAVA µε JProfiler To αντίστοιχο εργαλείο JProfiler για δυναµική ανάλυση προγραµµάτ ων JAVA 17-24 12