Lezione 14. Testing • • [S95, Cap. 22-23] [GMJ91, Sez. 6.3] Generalità Testing statistico, Defect testing, Regression testing Top down-, bottom up-, thread-, back to back-, stress-testing. Black box (functional) testing White box (structural) testing • Path testing e metrica ‘cyclomatic complexity’ 1 Generalità Testing è, principalmente, una forma di analisi dinamica della implementazione del sistema Rivela la presenza di errori, NON la loro assenza Consiste nel far funzionare il sistema in situazioni e con dati in input realistici, e nell’osservare output inattesi • se l’output corretto è definito formalmente, la verifica è automatizzabile Sebbene tecniche formali di analisi statica si stiano diffondendo, il testing rimane la tecnica predominante di V&V (ma vale un principio di complementarietà) 2 Testing stages Unit testing • Module testing • testing collections of modules integrated into sub-systems. Verify subsystem interfaces. System testing • testing of collections of dependent components Sub-system testing • testing of individual components testing the complete system prior to delivery. Functional + nonfunctional requirements: correttezza, performance, robustezza, interoperabilità, ... Acceptance testing • • testing by users (client), with real user data. Sometimes called alpha testing beta testing for systems to be marketed as products: limited distribution to potential customers (final users) 3 The V-model of development Requir ements specification System specification System integration test plan Acceptance test plan Service System design Acceptance test Puo far parte del Contratto Detailed design Sub-system integration test plan System integration test Module and unit code and tess Sub-system integration test Unit (procedure, class…) testing a volte è fatto direttamente dal programmatore, con il rischio di dati ‘addomesticati’... 4 Component testing / integration testing Integration testing Software developer Independent testing team Component testing • • • Component testing Testing of individual program components Usually the responsibility of the component developer (except for critical systems) Tests are derived from the developer’s experience Integration testing • • • Testing of groups of components integrated to create a system or subsystem The responsibility of an independent testing team Tests are based on a system specification 5 Il documento ‘Piano di Test’ Il documento serve a manager e ingegneri per pianificare le attività, allocare risorse, controllare progresso… Deve contenere questi elementi: • • • • • • Descrizione delle fasi del processo di testing da seguire Relazioni di copertura fra test e requirements (use-case driven…) Elenco degli artefatti da testare Definizione dei formati di registrazione dei risultati del testing, per eventuali ispezioni successive Testing schedule e allocazione di risorse; requisiti hardware e software Valutazione dei possibili problemi di staff, o di budget, per anticipare rischi Lo sviluppo del Piano di Test inizia assieme alla fase dei Requirements, e procede in parallelo con le altre attività del processo. 6 Test data - test cases Test data • Inputs which have been devised to test the system Test cases • Inputs to test the system and the predicted outputs if the system operates according to its specification 7 Defect testing process Test cases Design test cases Test data Prepare test data Test results Run program with test data Test reports Compare results to test cases 8 Defect testing e debugging Defect testing • • Debugging • • • • I test sono concepiti in modo da rivelare l’esistenza di errori (software faults) in unit, module, subsystem, system Per contrasto, acceptance (validation) testing mira a esibire il l’assenza di errori a fronte dei soli acceptance test cases concordati con il Cliente... Formulare ipotesi sul comportamento erroneo del programma Verificare le ipotesi attraverso nuovi test specifici Localizzare precisamente l’errore Correggerlo Debuggers • strumenti interattivi che visualizzano valori intermedi di variabili di programma, e tracce del flusso di controllo (statement eseguiti) 9 Debugging and regression testing Locate error Design error repair Repair error Re-test program Regression testing: test del sistema dopo la correzione di uno o piu’ errori, per escludere errori indotti. Nella fase di test planning, la identificazione di dipendenze fra sotto-sistemi e fra moduli consente di ottimizzare regression testing, limitandolo all’elemento incriminato e quelli da lui dipendenti. 10 Testing statistico I test sono concepiti in modo da riflettere le caratteristiche statistiche degli user input per i diversi profili di utente (viewpoints). • • Non si preoccupa di scoprire e correggere software faults, ma di... ... ottenere stime di affidabilità (reliability): probabilità di comportamento error-free, cioè senza software failures, rispetto a » un dato intervallo temporale, » uno specifico obiettivo (servizio), in un particolare contesto d’uso (viewpoint). Input possibili user1 user2 Input erronei user3 Producono output erronei, esponendo software faults (da localizzare con defect testing) 11 Software faults / software failures Mills et al. (1987): non tutti i software faults producono la stessa frequenza di software failures. In un caso, la rimozione del 60% dei faults ha ridotto solo del 3% le failures. • • • Risultati analoghi confermati da studi in IBM. In altri termini, un fault puo’ causare failure dopo anni di uso del software. A volte, fault noti (in funzionalità non essenziali) possono essere evitati dagli utenti, senza impatto negativo sulla reliability Fino a metà del budget per lo sviluppo può essere speso per il TESTING V&V costs Reliability 12 Testing strategies Top-down testing Bottom-up testing Thread testing Stress testing Back-to-back testing La tecnica usata puo’ dipendere dalla fase (module-, subsystem, system-testing) In ogni caso, conviene usare un approccio incrementale, che facilita la localizzazione dei difetti (--->) 13 Incremental (integration) testing Moduli o subsystems Tests A T1 T1 A T1 T2 A T2 T2 B B T3 T3 B C T4 T3 C T4 T5 D Test sequence 1 Test sequence 2 Test sequence 3 14 Top-down integration testing Level 1 Testing sequence Level 2 Level 1 Level 2 Le vel 2 . .. Level 2 Le vel 2 stubs Le vel 3 stubs Il sistema è rappresentato da una singola componente astratta, mentre le sotto-comp. son rappresentate da ‘stubs’ (mozzicone, moncherino): versioni a funzionalità limitata, ma interfaccia completa. + E’ conveniente quando anche il sistema e’ strutturato ad albero (e implementato in modo top-down). - Non sempre è possibile realizzare economicamente ‘stubs’ realistici - Non sempre la componente top produce output da osservare: vanno allora creati output artificiali - Non adatto a sistemi O-O, nei quali spesso non esiste una (unica) componente top 15 Bottom-up integration testing Test drivers Level N Test drivers Level N Level N–1 Le vel N Level N–1 Level N Level N Testing sequence Level N–1 16 Testa a partire dalle componenti di basso livello, e procede verso l’alto usando test drivers (l’opposto degli stubs), che simulano l’ambiente di componenti soprastanti ancora da implementare • E’ conveniente quando anche il sistema è organizzato a strati (e implementato in modo bottom-up) Test drivers e relative sequenze e dati di test possono essere distribuiti assieme alle componenti riutilizzabili - Trova errori nel design tardivamente + Adatto a sistemi O-O Tempi di sviluppo variabili per system components => necessità di usare simultaneamente test drivers e stubs 17 Thread testing (o ‘transaction-flow’ testing) Adatto a sistemi real-time e object-oriented Applicabile dopo che processi o oggetti sono stati testati individualmente Testa la sequenza di passi di calcolo (attraverso processi o oggetti) che scaturisce da un dato evento esterno. 18 Stress testing (for robustness) Exercises the system progressively beyond its maximum design load. • • Transactions per second in a DB system Number of terminals supported by an operating system Investigating failure behaviour: systems should not fail catastrophically, with unacceptable loss of service or data Particularly relevant to distributed systems which can exhibit severe degradation as a network becomes overloaded 19 Back-to-back testing Present the same tests to different versions of the system and compare outputs. Differing outputs imply potential problems Possible when • • a prototype is available or with regression testing of a new system version Reduces the costs of examining test results: automatic comparison of outputs 20 Back-to-back testing Test data Program version A Program version B Results comparator Difference report 21 Black-box (or functional) testing The program is considered as a ‘black-box’ ‘Functional’: observing the pure input-output relation The program test cases are based on the system specification ...thus test planning can begin early in the software process, as soon as the specification is available 22 A system from the viewpoint of Black-box testing Input test data I Inputs causing anomalous behaviour e System Output test results Oe Outputs which reveal the presence of defects 23 Equivalence classes of inputs Partition system inputs (or outputs) into equivalence classes, based on system spec. and intuition Invalid inputs System Valid inputs The program is expected to behave similarly (correctly or incorrectly) for all elements of the same class For each class: - in principle choose one test case - in practice choose average and boundary test cases (the latter are often overlooked by programmers) Inputs should be tuned to hit the desired elements of the output partitions Outputs 24 Equivalence partitions... …for a program accepting 4-10 input values greater than 10.000 3 4 Less than 4 7 11 10 Between 4 and 10 More than 10 Number of input values 9999 10000 Less than 10000 50000 100000 99999 Between 10000 and 99999 More than 99999 Input values 25 Search routine specification procedure Search (Key : ELEM ; T: ELEM_ARRAY; Found : in out BOOLEAN; L: in out ELEM_INDEX) ; Pre-condition -- the array has at least one element T’FIRST <= T’LAST Post-condition -- the element is found and is referenced by L ( Found and T (L) = Key) or -- the element is not in the array ( not Found and not (exists i, T’FIRST <= i <= T’LAST, T (i) = Key )) 26 Search routine - testing guidelines (for arrays in general) Test software with arrays of size 1 Use arrays of different sizes in different tests Derive tests so that the first, middle and last elements of the array are accessed Test with arrays of zero length (if allowed by programming language) 27 Search routine - input partitions and test cases Array Single value Single value More than 1 value More than 1 value More than 1 value More than 1 value Inp ut sequence (T) 17 17 17, 29, 21, 23 41, 18, 9, 31, 30, 16, 45 17, 18, 21, 23, 29, 41, 38 21, 23, 29, 33, 38 Eleme nt In sequence Not in sequence First element in sequence Last element in sequence Middle eleme nt in sequence Not in sequence Key (Key) 17 0 17 45 23 25 Output (Found, L) true, 1 false, ?? true, 1 true, 7 true, 4 false, ?? 28 White-box (or structural) testing The program is visible: derive of test cases and input partitions from program structure. Usually applied to small program units (subroutines, object methods) Objective is to exercise all program statements (not all arcs or all paths of the flow graph) Test data Tests Derives Component code Test outputs (In Black-box testing, test cases were derived from the specification) 29 class BinSearch { // This is an encapsulation of a binary s earch function that takes an array of // ordered objects and a key a nd returns an object with 2 attributes namely // index - the value of the array index // found - a boolean indicating whether or not the key is in the array // An object is returned because it is not possible in J ava to pass bas ic types by // reference to a function and so return two values // the key is -1 if the element is not found public static void search ( int key, i nt [] elemArray, Result r ) { int bottom = 0 ; int top = elemArray.length - 1 ; int mid ; r.found = fals e ; r.index = -1 ; while ( bottom <= top ) { mid = (top + bottom) / 2 ; if (elemArray [mid] == key) { r.index = mid ; r.found = true ; return ; } // if part else { if (elemArray [mid] < key) bottom = mid + 1 ; else top = mid - 1 ; } } //while loop } // s earch } //BinSearch Binary search (Java) program structure suggests to consider three input partitions, based on element mid... 30 Binary search equiv. partitions Equivalence class boundaries Elements < Mid Elements > Mid Mid-point 31 Binary search - test cases (cfr. pag. 28) Input array (T) 17 17 17, 21, 23, 29 9, 16, 18, 30, 31, 41, 45 17, 18, 21, 23, 29, 38, 41 17, 18, 21, 23, 29, 33, 38 12, 18, 21, 23, 32 21, 23, 29, 33, 38 Key (Key ) 17 0 17 45 23 21 23 25 Output (Found, L) true, 1 false, ?? true, 1 true, 7 true, 4 true, 3 true, 4 false, ?? 32 Path testing (un caso di white box testing) Objective is to exercise all program paths (implies exercising all arcs of the flow graph and all program statements) Based on Program flow graph • which describes the program control flow, focusing on branches and abstracting from assignements, I/O, procedure calls. if-then-else loop-while case-of and based on Cyclomatic complexity of flow graph ---> 33 Cyclomatic complexity - una metrica di qualità del software Cyclomatic complexity • • • introdotta da Thomas McCabe nel 1976, è forse la più usata metrica statica di programmi software misura il numero di cammini linearmente indipendenti attraverso un programma ignora l’effetto dei dati e l’annidamento di strutture di controllo Cyclomatic Complexity Risk Evaluation 1-10 11-20 21-50 greater than 50 a simple program, without much risk more complex, moderate risk complex, high risk program untestable program (very high risk) Cyclomatic number di un grafo G con n nodi, e archi e una componente connessa: C(G) = e - n + 1 34 Teorema - In un grafo G fortemente connesso, C(G) è uguale al numero massimo di cammini linearmente indipendenti Applicazione al testing • • • • • • associare a un programma strutturato a blocchi il grafo del flusso di controllo G, che avrà un solo entry point e un solo exit point ogni nodo corrisponda a un blocco di statements in cui il flusso di controllo è sequenziale gli archi rappresentino scelte del flusso di controllo aggiungere un arco da exit point a entry point per ottenere un grafo fortemente connesso Calcolare il cyclomatic number per trovare la dimensione della base di cammini linearmente indipendenti da testare, dato che… la base garantisce che tutti gli statements vengano eseguiti, e tutte le scelte esplorate. 35 Esempio astratto Grafo fortemente connesso (una componente) Archi = 11, Nodi = 7 Cyclomatic number = 11-7+1 = 5 a 1 2 b 3 4 d Numero max di cammini linearm. indipendenti = 5 7 b1: b2: b3: b4: b5: 6 5 e 8 c f 9 10 abcg a(bc)*2g abefg adefg adfg archi g Qualunque cammino è una combinazione lineare di b1-b5: abcbefg = b2 + b3 - b1 a(bc)*3g = 2*b2 - b1 36 Esempio Binary search - flow graph and cyclomatic complexity 1 CC(G) = 17 edges - 13 nodes + 1=5 (while Bott <= Top loop) 2 Cinque cammini linear. indip.: (if not Found then...) 3 4 (If T (mid) = Key then...) 5 6 7 8 9 10 12 (if T (mid) < Key then...) 1, 2, 12, 13 1, 2, 3, 4, 12, 13 1, 2, 3, 5, 6, 11, 2, 12, 13 1, 2, 3, 5, 7, 8, 10, 11, 2, 12, 13 1, 2, 3, 5, 7, 9, 10, 11, 2, 12, 13 In programmi strutturati, senza GOTO’s, CC(G) = numero di predicati elementari (2, 3, 5, 7) + 1 11 =5 13 (baco in Sommerville, che ne conta solo 4…) 37