Esercizi sul Testing “Working in progress”enrico/mmis/Testing_6_exercises.pdf · Overview...
Transcript of Esercizi sul Testing “Working in progress”enrico/mmis/Testing_6_exercises.pdf · Overview...
Esercizi sul Testing “Working in progress”
Filippo Ricca DISI, Università di Genova, Italy
Overview
Sistema Bibliografico (consigliato!) Da fare a casa e mandare via mail ….
Esercizio 1 - Black box testing Esercizio 2 - White box testing Esercizio 3 - Junit Esercizio 4 - Mutation + Junit Esercizio 5 - Three step approach
Generazione casi di test a partire da Use Cases
Esercizio 6 – State based testing 2
Sistema Bibliografico
Suppose we have to test a bibliographic system with Junit …
Document: author, title, and year of publication
Functionalities: Loading documents Add a document Search that information for values we
specify …
GUI
A casa …
A giorni sul vostro sito comparirà un package contenente: codice Java del sistema bibliografico specifiche dei casi di test da produrre procedura da seguire …
Voi dovrete scrivere i casi di test Junit seguendo le specifiche
date verificare che funzionano spedirmi un file .zip che li contiene
Esercizio 1 – black box testing
Scrivere dei casi di test black box per la seguente funzione Foo applicare equivalence partitioning e boundary analysis
Foo converte una sequenza di caratteri in un numero intero. Es. Foo(“123”)=123, Foo(“ 1”)=1 La sequenza può iniziare con un numero negativo. L’intero rappresentato dalla sequenza deve essere compreso
tra minint e maxint (minint = -32768 maxint = 32767) La funzione deve segnalare errore se la sequenza non e’
ammessa 6
Esercizio 1 – equivalence partitioning
Classe Classe valida (entro i limiti) Classe non valida
Numero intero ben formato
Positivo: Foo(“10”) -> 10 Foo(“ 10”) -> 10
Negativo: Foo(“-10”) -> -10 Foo(“ -10”) -> -10
Foo(“99999”) -> err
Foo(“-99999”) -> err
Numero non intero Foo(“3.7”) -> err Foo(“3.0E1”) -> err Foo(“1 1”) -> err
Stringa con caratteri alfanumerici
Foo(“a”) -> err Foo(“abcde”) -> err Foo(“a11”) -> err
7
Esercizio 1 – boundary analysis
8
Boundary condition
Foo(“32767”) -> 32767 Foo(“32768”) -> err Foo(“32766”) -> 32766
Foo(“0”) -> 0 Foo(“”) -> err Foo(“-“) -> err
Foo(“-32768”) -> -32768 Foo(“-32769”) -> err Foo(“-32767”) -> -32767
Esercizio 2 – white box testing Dato il seguente codice C
disegnare il CFG ricavare i casi di test per
copertura nodi (statement coverage) e archi (branch coverage).
Per casa ricavare i casi di test anche per i criteri “all paths” e “multiple condition”
9
int foo (int num1, int num2, int num3) {
if ((num1 < num2) || (num1 < num3)) printf("no ok“);
while (num2 > 0) { num1 = num1 - 1; num2 = num2 - 1; }
if (num1 == num3) printf("ok“); else printf("no ok“); }
OR
Esercizio 2 – CFG
10
int foo (int num1, int num2, int num3) {
if ((num1 < num2) || (num1 < num3)) // 1 printf("no ok“); // 2
while (num2 > 0) { // 4 num1 = num1 - 1; // 5 num2 = num2 - 1; }
if (num1 == num3) // 7 printf("ok“); // 8 else printf("no ok“); // 9 }
1 2
3 4
5 6
7 8 9
Esercizio 2 – statement
11
int foo (int num1, int num2, int num3) {
if ((num1 < num2) || (num1 < num3)) // 1 printf("no ok“); // 2
while (num2 > 0) { // 4 num1 = num1 - 1; // 5 num2 = num2 - 1; }
if (num1 == num3) // 7 printf("ok“); // 8 else printf("no ok“); // 9 }
1 2
3 4
5 6
7 8 9
T1 = 1,2,3 --> no ok, no ok T2 = 1,2,-1 --> ok
Esercizio 2 - branch
12
int foo (int num1, int num2, int num3) {
if ((num1 < num2) || (num1 < num3)) // 1 printf("no ok“); // 2
while (num2 > 0) { // 4 num1 = num1 - 1; // 5 num2 = num2 - 1; }
if (num1 == num3) // 7 printf("ok“); // 8 else printf("no ok“); // 9 }
1 2
3 4
5 6
7 8 9
T1 = 1,2,3 --> no ok, no ok T3 = 3,2,1 --> ok
Branch 3 not covered!
Esercizio 3 - Junit
Data la seguente implementazione di uno shopping cart progettare i casi di test Junit per avere statement coverage 100% della classe ShoppingCart. Package shopping:
Classe Product Classe ProductNotFoundException Classe ShoppingCart
13
14
public class Product { private String title; private double price; public Product (String t, double p) { this.title = t; this.price = p; } public String getTitle() { return title; } public double getPrice() { return price; } public boolean equals(Object o) { if (o instanceof Product) { Product p = (Product)o; return p.getTitle().equals(title); } return false; } }
public class ShoppingCart { private ArrayList items; public ShoppingCart() { items = new ArrayList(); } public double getBalance() { double balance = 0.00; for (Iterator i = items.iterator(); i.hasNext();){ Product item = (Product)i.next(); balance += item.getPrice(); } return balance; } public void addItem(Product item) { items.add(item); } public void removeItem(Product item) throws ProductNotFoundException { if (!items.remove(item)) { throw new ProductNotFoundException();} } public int getItemCount() { return items.size(); } public void empty() { items.clear(); } }
public class ProductNotFoundException extends Exception { public ProductNotFoundException() { super(); } }
15
public class ShoppingCartTest extends TestCase { private ShoppingCart cart; private Product book1;
protected void setUp() { cart = new ShoppingCart(); book1 = new Product("Unit Testing", 29.95); cart.addItem(book1); }
public void testEmpty() { cart.empty(); assertEquals(0, cart.getItemCount()); }
public void testAddItem() { Product book2 = new Product("Automation", 29.95); cart.addItem(book2); assertEquals(2, cart.getItemCount()); double expectedBalance = book1.getPrice() + book2.getPrice(); assertEquals(expectedBalance, cart.getBalance(), 0.0); }
public void testRemoveItem() throws ProductNotFoundException { cart.removeItem(book1); assertEquals(0, cart.getItemCount()); }
public void testRemoveItemNotInCart() { try { Product book3 = newProduct(“CMS", 29.95); cart.removeItem(book3); fail("Should raise a ProductNotFoundException"); } catch(ProductNotFoundException expected) { // successful test } } }
noting
Esercizio 4 – Junit + Mutation
Data la seguente implementazione della classe EURO e la seguente testsuite Junit: Verificare se le seguenti mutazioni sono killed e in
caso non lo siano aggiungere tests Junit che siano in grado di eliminarle ...
Euro:6: 0L -> 1L Euro:29: changed return value (ireturn)
Dopo avere completato la testsuite come richiesto al punto precedente cercare almeno una mutazione che generi ancora un mutante live
16
17
public class Euro {
private long valore;
public Euro(long euro, long cent) { if (euro >= 0) { valore = euro*100 + cent; } else { valore = euro*100 - cent; } }
public Euro(double d) { valore = (int)(d*100); }
public long getValore() { return valore; }
public Euro somma(Euro e) { this.valore = this.valore + e.getValore(); return this; }
public boolean ugualeA(Euro e){ if (valore == e.getValore()) return true; else return false; } }
Una possibile implementazione della classe EURO è quella di usare i “long” per rappresentare il valore interno:
Valore = euro*100 + cent
E poi fare i calcoli direttamente sul long ....
Es. Euro (1, 57) + Euro (3, 54) --> 157 + 354 = 511 cioè 5.11 euro
18
import junit.framework.TestCase;
public class EuroTest extends TestCase {
public void testConstructor() { Euro e = new Euro(5, 30); assertEquals(e.getValore(), 530, 0.0); }
public void testSomma() { Euro e1 = new Euro(5, 30); Euro e2 = new Euro(6, 20); Euro e3 = e1.somma(e2); assertTrue(e3.ugualeA(new Euro(11,50))); } }
EuroTest
19
public class Euro {
private long valore;
public Euro(long euro, long cent) { if (euro >= 0) { ---> if (euro >= 1) { valore = euro*100 + cent; } else { valore = euro*100 - cent; } }
public Euro(double d) { valore = (int)(d*100); }
public long getValore() { return valore; }
public Euro somma(Euro e) { this.valore = this.valore + e.getValore(); return this; }
public boolean ugualeA(Euro e){ if (valore == e.getValore()) return true; else return false; } }
Euro:6: 0L -> 1L
import junit.framework.TestCase;
public class EuroTest extends TestCase {
public void testConstructor() { Euro e = new Euro(5, 30); assertEquals(e.getValore(), 530, 0.0); }
public void testSomma() { Euro e1 = new Euro(5, 30); Euro e2 = new Euro(6, 20); Euro e3 = e1.somma(e2); assertTrue(e3.ugualeA(new Euro(11,50))); } }
Live!
20
public class Euro {
private long valore;
public Euro(long euro, long cent) { if (euro >= 0) { --- if (euro >= 1) { valore = euro*100 + cent; } else { valore = euro*100 - cent; } }
public Euro(double d) { valore = (int)(d*100); }
public long getValore() { return valore; }
public Euro somma(Euro e) { this.valore = this.valore + e.getValore(); return this; }
public boolean ugualeA(Euro e){ if (valore == e.getValore()) return true; else return false; } }
import junit.framework.TestCase;
public class EuroTest extends TestCase {
public void testConstructor() { Euro e = new Euro(5, 30); assertEquals(e.getValore(), 530, 0.0); }
public void testConstructorZero() { Euro e = new Euro(0, 30); assertEquals(e.getValore(), 30, 0.0); }
public void testSomma() { Euro e1 = new Euro(5, 30); Euro e2 = new Euro(6, 20); Euro e3 = e1.somma(e2); assertTrue(e3.ugualeA(new Euro(11,50))); } }
Euro:6: 0L -> 1L
Killed!
21
public class Euro {
private long valore;
public Euro(long euro, long cent) { if (euro >= 0) { valore = euro*100 + cent; } else { valore = euro*100 - cent; } }
public Euro(double d) { valore = (int)(d*100); }
public long getValore() { return valore; }
public Euro somma(Euro e) { this.valore = this.valore + e.getValore(); return this; }
public boolean ugualeA(Euro e){ if (valore == e.getValore()) return true; else return false; --> else return true } }
Euro:29: changed return value (ireturn)
import junit.framework.TestCase;
public class EuroTest extends TestCase {
public void testConstructor() { Euro e = new Euro(5, 30); assertEquals(e.getValore(), 530, 0.0); }
public void testConstructorZero() { Euro e = new Euro(0, 30); assertEquals(e.getValore(), 30, 0.0); }
public void testSomma() { Euro e1 = new Euro(5, 30); Euro e2 = new Euro(6, 20); Euro e3 = e1.somma(e2); assertTrue(e3.ugualeA(new Euro(11,50))); } }
Live!
22
public class Euro {
private long valore;
public Euro(long euro, long cent) { if (euro >= 0) { valore = euro*100 + cent; } else { valore = euro*100 - cent; } }
public Euro(double d) { valore = (int)(d*100); }
public long getValore() { return valore; }
public Euro somma(Euro e) { this.valore = this.valore + e.getValore(); return this; }
public boolean ugualeA(Euro e){ if (valore == e.getValore()) return true; else return false; --> else return true } }
Euro:29: changed return value (ireturn) import junit.framework.TestCase;
public class EuroTest extends TestCase {
public void testConstructor() { Euro e = new Euro(5, 30); assertEquals(e.getValore(), 530, 0.0); }
public void testConstructorZero() { Euro e = new Euro(0, 30); assertEquals(e.getValore(), 30, 0.0); }
public void testUguale() { Euro e1 = new Euro(5, 30); Euro e2 = new Euro(6, 20); assertTrue(e1.ugualeA(e1)); assertFalse(e1.ugualeA(e2)); }
public void testSomma() { Euro e1 = new Euro(5, 30); Euro e2 = new Euro(6, 20); Euro e3 = e1.somma(e2); assertTrue(e3.ugualeA(new Euro(11,50))); } }
Killed!
23
public class Euro {
private long valore;
public Euro(long euro, long cent) { if (euro >= 0) { valore = euro*100 + cent; } else { valore = euro*100 - cent; } }
public Euro(double d) { valore = (int)(d*100); }
public long getValore() { return valore; }
public Euro somma(Euro e) { this.valore = this.valore + e.getValore(); return this; }
public boolean ugualeA(Euro e){ if (valore == e.getValore()) return true; else return false; } }
import junit.framework.TestCase; public class EuroTest extends TestCase { public void testConstructor() { Euro e = new Euro(5, 30); assertEquals(e.getValore(), 530, 0.0); } public void testConstructorZero() { Euro e = new Euro(0, 30); assertEquals(e.getValore(), 30, 0.0); } public void testUguale() { Euro e1 = new Euro(5, 30); Euro e2 = new Euro(6, 20); assertTrue(e1.ugualeA(e1)); assertFalse(e1.ugualeA(e2)); } public void testSomma() { Euro e1 = new Euro(5, 30); Euro e2 = new Euro(6, 20); Euro e3 = e1.somma(e2); assertTrue(e3.ugualeA(new Euro(11,50))); } }
M FAIL: Euro:9: * -> / M FAIL: Euro:9: - -> + M FAIL: Euro:14: CP[25] 100.0 -> 201.0
Mutazione che generi un mutante live?
Esercizio 5 – Three step approach
Lo scopo di EasyMarks è quello di fornire un valido aiuto ad un docente universitario per la gestione dei risultati degli studenti che seguono i suoi corsi.
Scrivere una serie di casi di test a partire dallo Use Case Inserire corso utilizzando la tecnica “three-step” approach
24
Use case diagram
25
26
Use case: Inserire Corso Primary Actors: Docente Intention in Context: Il Docente vuole inserire un corso nel Sistema Postcondition: Il corso è presente nel Sistema ed è configurabile. Main Success Scenario: 1. Il Docente chiede di inserire un corso. 2. Il Sistema chiede i dati del corso (** 1). Interface_View 3. Il Docente li inserisce. 4. Se i dati sono validi (** 2), il Sistema chiede conferma al Docente. 5. Il Docente conferma, il Sistema inserisce il corso. Lo Use Case termina con successo. Extensions: 4a. Se i dati non sono validi, il Sistema informa di ciò il Docente, ed il corso non è inserito. Lo Use Case fallisce. 5a. Il Docente non conferma. Lo Use Case fallisce.
(** 1) Dati del corso: nome, anno accademico (un intero), descrizione, e date di inizio e fine. Un solo intero A è sufficiente dato che individua l’anno accademico A/A+1.
(** 2) I dati del corso sono validi se la data di fine è successiva a quella di inizio, ed entrambe sono comprese nell’anno accademico (l’anno accademico xx/xx+1 va dal 1 Settembre xx al 1 Marzo xx+2) e non esiste un altro corso con lo stesso nome e stesso anno accademico.
Generare gli scenari
27
Name Starting Alternative Scenario 1: Inserimento riuscito Basic flow Scenario 2: Inserimento di un corso gia' esistente Basic flow 4a Scenario 3: Inserimento della data di fine precedente alla data di inizio
Basic flow 4a
Scenario 4: Inserimento di una data non compresa nell'anno accademico specificato
Basic flow 4a
Scenario 5: Il docente non conferma Basic flow 5a
Generare i quasi test-cases
28
Test id
Scenario/ condition
Nome aa DataInizio DataFine Fine>Inizio Data compresa
Corso non esistente
Expected result
1 Inserimento riuscito
V V V V V V V Il corso è inserito
2 Inserimento di un corso gia' esistente
V V V V V V I Messaggio d’errore: Esiste gia' un corso con lo stesso nome e anno
3 Inserimento della data di fine precedente alla data di inizio
V V V V I N/A V Messaggio d’errore: Le date di inizio e fine corso non sono corrette
4 Inserimento di una data non compresa nell'anno accademico
V V V V V I V Messaggio d’errore: Le date di inizio e fine corso non sono comprese nell'anno accademico
5 docente non conferma
V V V V V V V Il corso non viene inserito
Casi di test completi
29
Test id Scenario/ condition
Nome aa Descrizione DataInizio DataFine
1 Inserimento riuscito
IS 2007 Ingegneria del software 20/09/07 31/03/08
2 Inserimento di un corso gia' esistente
IS 2007 Ingegneria del software 20/09/07 31/03/08
3 Inserimento della data di fine precedente alla data di inizio
CDI 2008 Calcolo differenziale ed integrale
20/09/09 31/03/09
4 Inserimento di una data non compresa nell'anno accademico specificato
CDI 2008 Calcolo differenziale ed integrale
20/09/00 31/03/09
5 Il docente non conferma
IS 2007 Ingegneria del software 20/09/07 31/03/08
Esercizio 6 – State based testing
Dalla seguente “descrizione testuale + interfaccia” ricavare la state machine per la classe calcolatrice
Successivamente: 1. Scrivere un unico caso di test
Junit in grado di coprire tutti i nodi
2. Scrivere una testsuite per conseguire transition coverage
Calcolatrice
All’inizio possono essere solo digitate delle cifre Successivamente viene digitata l’operazione Altre cifre Uguale (=) E viene stampato il risultato ….
1234 + 12 = 1246
Metodi
La classe calcolatrice è dotata dei seguenti metodi:
aggiungiCifra() per digitare una cifra sullo schermo
inserisciOp() per digitare un operazione uguale() per ottenere il risultato reset() per far ripartire il totalizazzatore da zero
FSM - calcolatrice
niente
Crea()
Cifra uno
aggiungiCifra()
aggiungiCifra()
Operazione inserisciOp()
Cifra due
aggiungiCifra()
aggiungiCifra()
risultato uguale()
aggiungiCifra()
inserisciOp()
niente reset()
inserisciOp()
Caso di test Junit public class CalcTester extends TestCase { public void testCalc() {
Calcolatrice c = new Calcolatrice(); c.aggiungiCifra(2); c.aggiungiCifra(4); c.inserisciOp(“+”),
assertTrue(“Operazione”, c.getStato()); c.aggiungiCifra(4); c.uguale(); assertTrue(“Uguale”, c.getStato()); assertTrue(28, c.getRisultato()); } }
Transition coverage
Crea(); AC(); AC(); OP(); AC(); AC(); Uguale() Crea(); AC(); OP(); AC(); Uguale(); OP(); AC(); Uguale() Crea(); AC(); OP(); AC(); Uguale(); AC(); OP(); AC(); Uguale() Crea(); AC(); OP(); AC(); OP(); AC(); Uguale() Crea(); Reset() Crea(); AC(); Reset() Crea(); AC(); AC(); OP(); Reset(); Crea(); AC(); OP(); AC(); Reset(); Crea(); AC(); OP(); AC(); Uguale(); Reset()