13-user interface testing2012 - unina stidue: l'universita ...unina.stidue.net/ingegneria del...
TRANSCRIPT
User Interface Testing 1
Software Testing
User Interface Testing
User Interface Testing 2
Sistemi basati sugli eventi
• Le interfacce utente rappresentano un caso di sistema ad eventi– Il sistema è in uno stato stabile fino all’intervenire di un evento utente, che fa partire un codice di event handling
• Anche un calcolatore, dotato di sistema delle interruzioni, può essere considerato come un sistema ad eventi– Un segnale è in grado di avviare un’interruzione, che viene successivamente servita
• I moderni sistemi distribuiti a sensori devono essere considerati sistemi ad eventi– Ogni dispositivo è in grado sia di ricevere input, che di elaborarli
User Interface Testing 3
Testing di sistemi interattivi
• Il testing di sistemi interattivi (in particolare di interfacceutente) viene condotto tipicamente in maniera black box
• Tipicamente i casi di test sono progettati tenendo in contole possibili interazioni che un utente può eseguiresull’interfaccia utente
– Per poter approcciare il problema del testing è fondamentale la disponibilità di un modello descrittivo delle interazioni utente-macchina
– Quali modelli sono utilizzabili per modellare UI?
User Interface Testing 4
Modellazione delle interazioni
• Il modello più comune è un modello di Macchina a stati: – Gli elementi fondamentali di una UI sono:
• Finestre e relativi Widget, dotati di– Eventi che possono essere eseguiti dagli utenti
– Campi, che possono essere eventualmente settati
• Si suppone che l’interfaccia utente non esegua alcunaoperazione se non in seguito a sollecitazioni da parte degliutenti– Lo “stato” dell’interfaccia utente viene modellato da uno stato di un automa
– L’esecuzione di eventi sulla UI (es. Click su button…) vienemodellata come ingressi impulsivi che scatenano transizioninell’automa
– Gli input immessi sono modellati come ingressi a livelli da cui dipende la transizione che si verifica
User Interface Testing 5
Esempio- modello di FSM per una UI
Logged As Admin
List of Films
Film Information
Click on "Add new film"
Click on "Cancel"
Click on"Search"
Click on"Back"
Click on
"film's link"Click on
"Cancel"
Click on
"Back"
Film Information
+ Search Movie
Click on"Back"
Click on"Cancel"
Movie Inserted
Click on
"Insert"
Click on"OK"
Click on
"film's link"
Click on"Search"
Search Movie
Film
Information +
list of film
Es.: L’FSM che descrive l’evoluzione di una UI per l’ esecuzione di un Caso d’Uso
User Interface Testing 6
Testing delle interfacce
• Gli input dei casi di test devono essere indicati sotto forma di sequenze di valori di input ed eventi daeseguire.– A seconda dei criteri di copertura (es. Stati, Eventi, Transizioni, path…), si progetteranno diversi TC
– Es.: click (add-film),click(search), click(filmlink),click(insert), click(OK) è il TC che permette dieseguire il cammino in rosso (Scenario: Inserimento Film OK)
• Ad una sequenza di valori di input dovrebbecorrispondere una sequenza di stati visitati e dioutput riscontrati.
User Interface Testing 7
Esempio- modello di FSM per una UI
Logged As Admin
List of Films
Film Information
Click on "Add new film"
Click on "Cancel"
Click on"Search"
Click on"Back"
Click on
"film's link"Click on
"Cancel"
Click on
"Back"
Film Information
+ Search Movie
Click on"Back"
Click on"Cancel"
Movie Inserted
Click on
"Insert"
Click on"OK"
Click on
"film's link"
Click on"Search"
Search Movie
Film
Information +
list of film
Es.: Cammino di esecuzione che esercita un certo scenario del Caso d’Uso
User Interface Testing 8
Possibile problema
• Come ottenere un FSM che descriva adeguatamente l’UI e che possa essere usato per progettare i casi di Test?
• Due possibilità: – FSM prodotto in fase di sviluppo dell’applicazione (ma può essere poco aderente all’effettiva implementazione fatta dell’UI)
– FSM ricostruito per Reverse Engineering a partire dalla UI effettivamente implementata (richiede tecniche di analisi statica o dinamica)
– Nel caso di Interfacce Dinamicamente Configurabili (es. di RichInternet Applications) piuttosto che Statiche, l’analisi statica non è sufficiente! Necessità di definire tecniche e strumenti di RE per la generazione (semi-automatica) del modello.
User Interface Testing 9
Esempio in Java
public JMenu createOptionMenu()
{
JMenu m = new JMenu("Scientifica");
JMenuItem item = new JMenuItem();
class itemListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
try{
op1 = Double.parseDouble(text.getText());
}
catch(NumberFormatException ecc)
{
text.setText("Errore: nessun valore inserito!");
return;
}
operazione = RADICE_QUADRATA;
invio.doClick();
}
}
…
}
Menu generato a run time
Voce di Menu generata a run time
Ascoltatore dichiarato a run time
Codice dell’ascoltatore dichiarato a run time
Non è, in generale, possibile, scrivere metodi di test che si riferiscono a
oggetti, classi e metodi che vengono dichiarati a run-time
User Interface Testing 10
Problema degli stati equivalenti
• Per poter astrarre un modello a stati è necessario poter decidere quando due stati coincidono– Siccome qualsiasi valore di qualsiasi variabile può caratterizzare lo stato, il numero di stati possibili è potenzialmente illimitato
– Per poter implementare dei criteri di equivalenza è necessario selezionare piccoli sottoinsiemi di informazioni, ma così facendo si rischia di non considerare informazioni importanti
• Nel nostro caso, una tecnica consiste nel considerare solo informazioni relative all’interfaccia utente, non allo stato interno dell’applicazione
• Da un modello FSM con un numero possibile di stati, è possibile ricavare test suite che vanno a coprire tutti i nodi o tutti gli archi– Un oracolo è dato dall’equivalenza dello stato raggiunto in ogni istante del test con quello descritto dal modello
User Interface Testing 11
Modello Event Interaction Graph
• Un altro modello utilizzato in letteratura èl’EIG (Event Interaction Graph)– Un grafo i cui nodi sono eventi e i cui archi orientati rappresentano relazioni di sequenzialità tra eventi
– Un cammino su un EIG corrisponde ad una sequenza di eventi, quindi ad un caso di test possibile
– Problema: l’EIG è, potenzialmente, illimitato• Si possono generare test suite che coprono l’EIG a
meno di un certo valore massimo di profondità(lunghezza) del caso di test
• L’unico oracolo automatico è dato dalla possibilità di eseguire effettivamente l’evento seguente
User Interface Testing 12
Automatizzazione
• Per poter eseguire automaticamente casi di test su interfacce utente sono necessari:– Strumenti che consentano di emulare il comportamentodell’utente, in particolare:
• Settare valori di input
• Scatenare eventi
– Strumenti che consentano di analizzare le interfacce restituite
• Tramite asserzioni sui widget presenti nell’interfaccia e I loro valori
User Interface Testing 13
Un esempio: Selenium
• Consideriamo il framework Selenium, a supporto del testing di interfacce utente di applicazioni Web
– http://selenium.openqa.org/
• Selenium offre quattro modalità di utilizzo:– Selenium IDE
– Selenium Core
– Selenium Remote Control
– Selenium Grid
User Interface Testing 14
Selenium IDE
• Si tratta di un’estensione di un browser checonsente di: – catturare le interazioni tra un utente e una applicazione web (fase di Capture)
– “suggerire” asserzioni relative alla presenza di widget sull’interfaccia utente
– replicare l’esecuzione di casi di test, mantenendo un log degliesiti dei test (fase di Replay)
• Selenium è dunque usabile per progettare TC anche a prescindere da un modello formalizzato (es. FSM) dellaUI.
• Utile per l’esecuzione di Testing di Accettazione
User Interface Testing 15
Capture
In fase di capture, Selenium IDE mantiene un log delle operazionieffettuatedall’utente e delleasserzioni da egliproposte
User Interface Testing 16
Replay
In fase di replay, Selenium IDE esegueautomaticamente test generati in fase dicapture, mantenendostatistiche sul numerodi test terminati con successo e falliti
User Interface Testing 17
Codice generato
In fase di capture, Selenium IDE genera anche del codice sorgente (a scelta in Java, C#, Perl, PHP, Python o Ruby) che può essereeseguitoindipendentemente daSelenium IDE
Il codice generato necessita, per essere eseguito, dipackages forniti con Selenium (che formano ilSelenium Core)
User Interface Testing 18
"Twenty percent of all input forms filled out by people contain bad data."- Dennis Ritchie, More Programming Pearls: Confessions of a Coder by Jon Louis Bentley
User Interface Testing 19
Validazione dell’input
• Un tipico problema del testing delle interfacce utente è la verifica della validitàdei dati di input– E’ la causa di molti attacchi (exploit) contro le applicazioni
– Ad esempio, in linguaggi a puntatori, come C, l’immissione di una stringa troppo lunga in input, in mancanza di validazione, può portare a sovrascrivere altri dati o addirittura zone di codice del programma stesso
– In linguaggi interpretati, come quelli spesso usati per il web, il problema è ancora più sentito
User Interface Testing 20
Il problema della Il problema della validazionevalidazione degli inputdegli input
�La validazione dei dati può essere fatta sia sul lato client che sul lato server
�La validazione sul lato client ha il vantaggio di utilizzare tempo di CPU
della macchina client piuttosto che quello della macchina server
�La validazione sul lato client può essere però scavalcata da un utente
malintenzionato che vada a sollecitare il server con una richiesta http che
non sia passata per la pagina client: in questo caso il server potrebbe avere
delle anomalie
La soluzione più corretta è quella di porre la validazione sia
sul lato client che sul lato server, in modo da bloccare la
maggior parte delle richieste scorrette sul client
(risparmiando risorse sul server). Solo le richieste fraudolente
verrebbero così bloccate dalla validazione lato server
User Interface Testing 21
Esempio: CrossEsempio: Cross--SiteSite ScriptingScripting
�Si verifica quando uno script lato client, inserito maliziosamente in un
campo di input, viene eseguito sulla macchina client di un utente ignaro
Sign.htmlSign.htmlSign.htmlSign.html<form method="post" action="sign.asp">
<textarea name="txtMessage"></textarea>
<input type="submit" value="Sign!">
</form>
Sign.aspSign.aspSign.aspSign.asp<% Message=request.form("txtMessage")
conn=OpenDBConnection
set rs=server.createobject("Adodb.recordset")
rs.open "Guestbook",conn,1,2,2
rs.Addnew
rs("Message")=Message
rs.update
%>
Guestbook.aspGuestbook.aspGuestbook.aspGuestbook.asp<% conn=OpenDBConnection
rs=server.createobject("Adodb.recordset")
rs.open "SELECT Message FROM GuestBook" ,
conn,3,3
%>
<table>
<% rs.movefirst
while not(rs.eof)
response.write (rs.fields("Message"))
rs.movenext
wend
%>
</table>
<% rs.close
set rs=nothing
conn.close
set conn=nothing
%>
Message=Server.HtmlEncode(Message)
User Interface Testing 22
Testing White Box di GUI
• Il testing white box (o comunque la progettazione di classi di test di unità) per GUI è reso difficile da alcuni fattori:– Molto spesso le classi della GUI sono istanziate a run-time, così come i metodi ascoltatori degli eventi
• Molto difficile scrivere dei driver che riescano ad emulare le stesse esecuzioni del programma originale
– Problemi di concorrenza: i test agiscono in un thread separato da quello che crea l’interfaccia, per cui bisogna anche misurarsi con le difficoltà relative alla tempificazione delle azioni di test
User Interface Testing 23
Java Robot (awt)
• La classe Robot consente l’esecuzione programmatica di eventi sull’interfaccia utente (limitatamente ad awt)– Ha metodi che riproducono le azioni del mouse ed eventi che riproducono la pressione di tasti
• Documentazione: http://download.oracle.com/javase/1.4.2/docs/api/java/
awt/Robot.html
• Un tutorial: http://forum.codecall.net/java-
tutorials/25923-robot-class.html
User Interface Testing 24
Esempio Java Robot
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.InputEvent;
public class MovingMouseDemo {
public static void main(String[] args) {
try {
Robot robot = new Robot();
robot.mouseMove(200, 200);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.mouseWheel(-100);
} catch (AWTException e) {
e.printStackTrace();
}
}
}
Il problema principale è quello di poter nominare gli oggetti dell’interfaccia (ad esempio InputEvent.BUTTON1_MASK) quando essi sono dinamicamente generati
User Interface Testing 25
UISpec4J
• UISpec4J è una libreria a supporto del testing funzionale e di unità di applicazioni Java con interfaccia utente basata su Swing, che fa uso di Junit
• In pratica, mette a disposizione metodi e oggetti che consentono di interrogare direttamente gli elementi dell’interfaccia utente – Strumenti analoghi: librerie di Selenium per le interfacce client di WA e Robotium per Android
• http://www.uispec4j.org/
User Interface Testing 26
Test Case in UI Spec
• Una classe di test UISpec va ad estendere la classe UISpecTestCase– public class AddressBookTest extends
UISpecTestCase
• Per poter eseguire i test mantenendo un punto di controllo sull’applicazione sotto test, il metodo setup conterrà (il parametro String[0] rappresenta la linea di comando, in questo caso vuota, della chiamata dell’applicazione):– protected void setUp() throws Exception {
setAdapter(new MainClassAdapter(Main.class,
new String[0])); }
User Interface Testing 27
Esempio: Calcolatrice (1/2)
package Calcolator;
import org.uispec4j.*
public class TestWhiteBox extends UISpecTestCase {
private Window main;
protected void setUp() throws Exception {
setAdapter(new MainClassAdapter(Starter.class, new String[0]));
main = getMainWindow();
}
public void testSumOK() throws Exception{
Button num1 = main.getButton("4");
num1.click();
Button plus = main.getButton("+");
plus.click();
Button num2 = main.getButton("4");
num2.click();
Button equals = main.getButton("=");
equals.click();
assertEquals("8.0",main.getTextBox().getText());
}
• La finestra principale è ottenuta col metodo getMainWindow()
• I riferimenti ai Button sono ottenuti con getButton(String) in base all’etichetta che essi mostrano
• Il riferimento alla TextBox è ottenuto con getTextBox() approfittando della circostanza che essa è unica, in tale interfaccia
User Interface Testing 28
Esempio: Calcolatrice (2/2)
package Calcolator;
import org.uispec4j.*
public class TestWhiteBox extends UISpecTestCase {
private Window main;
protected void setUp() throws Exception {
setAdapter(new MainClassAdapter(Starter.class, new String[0]));
main = getMainWindow();
}
public void testSenoNotOK() throws Exception{
Button numc1 = main.getButton("3");
numc1.click();
Button numc2 = main.getButton(".");
numc2.click();
Button numc3 = main.getButton("1");
numc3.click();
Button numc4 = main.getButton("4");
numc4.click();
MenuItem menu=
main.getMenuBar().getMenu("Scientifica");
menu.click();
MenuItem menu2= menu.getSubMenu("Seno");
menu2.click();
assertEquals("0.0015926529164868282",main.getT
extBox().getText());
• Il riferimento al menu è ottenuto con i metodi getMenuBar().getMenu(String), dove la String è l’etichetta visualizzata del Menu
• L’asserzione è una asserzione tra stringhe, per cui assertEquals è ben posto; se si fosse trattato di un confronto tra reali si sarebbe dovuto utilizzare un asserzione del tipo:– AssertTrue (Math.abs(valoreAtteso-valoreOttenuto)<epsilon)
User Interface Testing 29
Esecuzione dei Test Case
• L’esecuzione dei test si ottiene sfruttando il framework Junit
• Ulteriori metodi possono essere personalizzati per poter individuare gli elementi dell’interfaccia in altri modi
• E’ possibile interagire anche con i Dialog
• Ulteriori informazioni sono disponibili nel tutorial all’indirizzo:
http://www.uispec4j.org/tutorial
User Interface Testing 30
Considerazioni su UISpec4J
• UISpec4J è uno strumento molto semplice e abbastanza potente, a supporto del testing di interfacce utente Swing (le più diffuse) di applicazioni Java interattive
• UISpec4J estende Junit e può essere utilizzato in tutti i processi nei quali viene utilizzato quest’ultimo– Progettazione di casi di test da parte dello sviluppatore, per il testing di unità
– Progettazione di casi di test per il testing funzionale black box
• UISpec4J si presta poco alla generazione automatica di casi di test, ma è naturalmente sempre utilizzabile per l’esecuzione automatica e la valutazione automatica dell’esito dei test
User Interface Testing 31
Abbot e Costello
• Abbot e Costello sono un’altra coppia di tool che aiuta nella programmazione di casi di test per interfacce utente Java (sia AWT che Swing).– Abbot è un insieme di librerie a supporto dell’esecuzione dei test case realizzati
• Abbot può essere utilizzato in maniera analoga a UISpec4J
– Costello è uno strumento interattivo che fornisce feature per il capture, l’editing, l’esecuzione, la visualizzazione dei risultati dei test ed altro
http://abbot.sourceforge.net/doc/overview.shtml
User Interface Testing 32
Uno scenario di utilizzo di Costello
• Creazione di un nuovo caso di test1. File/New Script:2. Imposta classe e metodo di
partenza e posizione del jar3. Cattura/All Actions4. Esegui un esempio di
esecuzione sull’applicazione da testare
5. Premi Shift+F1 dopo aver posizionato il puntatore sul campo da usare per l’asserzione
6. Imposta un’asserzione7. Termina8. File/Save (in formato XML)
User Interface Testing 33
Uno scenario di utilizzo di Costello
• Esecuzione di un caso di test1. File/New
Script
2. Seleziona una test suite
3. Esegui
4. Verifica l’esito delle asserzioni
User Interface Testing 34
Utilizzo di Abbot
• Abbot da solo può essere utilizzato in maniera simile ad UISpec4J, per scrivere test, in particolare anche test di unità di singoli componenti:
User Interface Testing 35
Android Testing: generalità
Un’applicazione Android in senso lato è composta di un lato client e di una o più tipologie di risorse lato server– Web Applications, Web Services, Risorse REST …
Ci si limiterà allo studio delle problematiche del testing della parte client, la cosiddetta app
Una app Android è sostanzialmente un’applicazione interattiva sottoposta a:– Eventi utente (eventi touch, segnali da sensori)
– Eventi di sistema (interruzioni, segnali broadcast)
User Interface Testing 36
Android Testing: generalità
E’ necessario definire, adattandoli all’ambiente Android:
– test models, per rappresentare le tipologie di elementi e interazioni da considerare e procare;
– testing levels, che specifichino i diversi punti di vista e obiettivi rispetto ai quali viene progettato il testing;
– test strategies, che definiscono obiettivi, euristiche e algoritmi da seguire nella progettazione dei casi di test;
– testing processes, che definiscono le modalità di esecuzione dei processi per il testing delle applicazioni Android;
– testing tools, strumenti a supporto delle attività di testing, in particolare a supporto della loro automazione
User Interface Testing 37
Unit Testing
Che cosa è possibile considerare come unità, nel testing di un’applicazione Android?– Activity
– Service
– Broadcast Receiver
– Content Provider
– Classi Java semplici, che non estendono classi del framework Android
User Interface Testing 38
Testing con JUnit
E’ possibile utilizzare un framework come Junit per le applicazioni Android (in particolare per le Activity)?
– Problema: una sola activity può accedere attivamente all’interfaccia utente.
– Soluzione: un framework di testing che esegua la activity sotto testing come sua parte, utilizzando funzionalità di instrumentazione per poterla monitorare
• In questo modo, è possibile pensare di testare una Activity scrivendo dei classici Android JUnit Test Cases, nell’ambito, però, di un project separato
– Da notare che il progetto di test e il progetto da testare devono avere la stessa signature (di solito si usa quella pubblica di debug)
http://developer.android.com/guide/topics/testing/activity_testing.html
User Interface Testing 39
Android Test Architecture
User Interface Testing 40
Creazione di un progetto di test
Da linea di comando si può scrivereandroid create test-project -m <main_path> -n <project_name> -p <test_path>
In Eclipse è sufficiente utilizzare il widget di creazione progetto
User Interface Testing 41
Manifest di un progetto di test
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.porfirio.orariprocida2011.test"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="4" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.porfirio.orariprocida2011" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<uses-library android:name="android.test.runner" />
</application>
</manifest>
Controlla l’esecuzione delle classi del package
User Interface Testing 42
Creazione di una classe di test
Utilizzo di JUnit3
User Interface Testing 43
Metodi generati
package com.porfirio.orariprocida2011.test;
import com.porfirio.orariprocida2011.OrariProcida2011Activity;
import android.test.ActivityInstrumentationTestCase2;
public class OrariProcida2011ActivityTests extends
ActivityInstrumentationTestCase2<OrariProcida2011Activity> {
public OrariProcida2011ActivityTests() {
super("com.porfirio.orariprocida2011", OrariProcida2011Activity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
}
User Interface Testing 44
Primi test case
…
public class OrariProcida2011ActivityTests extends
ActivityInstrumentationTestCase2<OrariProcida2011Activity> {
private OrariProcida2011Activity mActivity;
private TextView mTextView1;
private ListView mListView;
@Override
protected void setUp() throws Exception {super.setUp();
mActivity = this.getActivity();
mTextView1=(TextView) mActivity.findViewById(R.id.textView1);
mListView =(ListView) mActivity.findViewById(R.id.listMezzi);
}
public void testPreconditions() {
assertNotNull(mTextView1);
assertNotNull(mListView);
}
public void testTextView1(){
String resourceString = new
String(mActivity.getString(com.porfir
io.orariprocida2011.R.string.mezzo));
assertEquals(resourceString,(String)mTextView1.
getText());
}
protected void tearDown() throws Exception
{
super.tearDown();
}
}
Oggetti utilizzati nel test
Precondizioni: esistenza degli oggetti utilizzati nel test
Test sul corretto valore di una casella di testo
User Interface Testing 45
Esecuzione dei test
Da Eclipse Run as Junit Test
Sequenza di esecuzione (Console)
[2011-11-16 19:33:36 - OrariProcida2011Testing] ------------------------------
[2011-11-16 19:33:36 - OrariProcida2011Testing] Android Launch!
[2011-11-16 19:33:36 - OrariProcida2011Testing] adb is running normally.
[2011-11-16 19:33:36 - OrariProcida2011Testing] Performing
android.test.InstrumentationTestRunner JUnit launch
[2011-11-16 19:33:36 - OrariProcida2011Testing] Automatic Target Mode: using existing emulator
'emulator-5554' running compatible AVD 'AVD_1_6'
[2011-11-16 19:33:36 - OrariProcida2011Testing] Uploading OrariProcida2011Testing.apk onto
device 'emulator-5554'
[2011-11-16 19:33:36 - OrariProcida2011Testing] Installing OrariProcida2011Testing.apk...
[2011-11-16 19:33:40 - OrariProcida2011Testing] Success!
[2011-11-16 19:33:40 - OrariProcida2011Testing] Project dependency found, installing:
OrariProcida2011
[2011-11-16 19:33:44 - OrariProcida2011] Application already deployed. No need to reinstall.
[2011-11-16 19:33:44 - OrariProcida2011Testing] Launching instrumentation
android.test.InstrumentationTestRunner on device emulator-5554
[2011-11-16 19:33:44 - OrariProcida2011Testing] Collecting test information
[2011-11-16 19:33:48 - OrariProcida2011Testing] Sending test information to Eclipse
[2011-11-16 19:33:48 - OrariProcida2011Testing] Running tests...
[2011-11-16 19:34:23 - OrariProcida2011Testing] Test run finished
User Interface Testing 46
Un test più complesso
Esempio di test che interagisce con l’interfaccia utente, settando un valore di uno Spinner
public void testListaVuota(){
mActivity.runOnUiThread(
new Runnable() {
public void run() {
mSpnPortoPartenza.setSelection(1);
mSpnPortoArrivo.setSelection(1);
assertEquals(0,(int)mListView.getCount());
}
});
mInstrumentation.waitForIdleSync();
}
Per settare un campo di una oggetto sulla UI, è necessario, in Android, farlo interagendo nello stesso thread della UI stessa
Per impedire la concorrenza tra eventi dell’utente reale ed eventi simulati da test
setActivityInitialTouchMode(false);
User Interface Testing 47
Activity Testing
Finora sono stati esemplificati casi di test riguardanti l’interazione con la UI in un’Activity
Altri possibili test da eseguire su di una Activity:– Testing in risposta a eventi riguardanti il ciclo di vita dell’Activity
– Testing in risposta ad eventi di sistema
– Testing in risposta ad eventi provenienti da sensori
User Interface Testing 48
Testing del ciclo di vita di un Activity
Per simulare una pausa e resume, ad esempio:Instrumentation mInstr = this.getInstrumentation();
mInstr.callActivityOnPause(mActivity);
mInstr.callActivityOnResume(mActivity);
User Interface Testing 49
Testing in isolamento
Per realizzare Unit Testing è necessario limitare al minimo e controllare le dipendenze dell’unità testata dal resto del software e dell’ambiente di esecuzione
La classe IsolatedContext è in grado di riprodurre un contesto di esecuzione fittizio, da utilizzare tutte le volte che sia necessario, senza dipendere dal reale stato del sistema
Per emulare gli eventi di sistema si possono utilizzare le classi del package android.hardware– Per emulare I sensori si possono usare le classi Sensor, SensorEvent, SensorEventListener e SensorManager, ridefinendole in modo che generino eventi fittizi
User Interface Testing 50
Esempio Mock
SMSReceiver è un Broadcast Receiver che ascolta per la ricezione di SMS
SMS è una Activity che viene avviata da SMSReceiver in seguito alla ricezione di un SMS e ne visualizza il testo
MockProvider è una classe che estende Thread e, tramite Intent si dichiara (tramite Intent) in grado di inviare SMS e controllarne il delivery
SMSMock è una classe che estende SMS, imitandolo. In pratica definisce e avvia un MockProvider
SMSTesting è una classe di test che, così come SMSMock, definisce e avvia un MockProvider e gli chiede di inviare un messaggio, come prova
User Interface Testing 51
Class Diagram
SMSTesting istanzia SMSMock e MockProvider
SMSMock sostituisce il metodo onCreate di SMSActivity e, istanziandosi, avvia MockProvider e lo dichiara come gestore degli SMS (al posto di un reale fornitore)
MockProvider dichiara due Intent corrispondenti a eventi di Invio e Consegna del messaggio
SMSTesting chiede a MockProvider di “inviare” un messaggio
SMSReceiver riceve i messaggi fittiziamente inviati da MockProvider e li gestisce come se fossero reali
SMSReceiver<<Broadcast Receiver>>
+onReceive()
SMSActivity<<Activity>>
+onCreate()
MockProvider<<Thread>>
+sendMessage()
SMSMock
+onCreate()
SMSTesting
+test()
11
User Interface Testing 52
Codice
...
public class SmsTesting extends ActivityInstrumentationTestCase2<SMSMock> {private SMSMock myActivity;
private MockProvider mymockprov;
...
@Override
protected void setUp() throws Exception{
super.setUp();
setActivityInitialTouchMode(false);
mymockprov = new MockProvider(SmsManager.getDefault(),getInstrumentation().getContext());
}
public void testcase1(){mymockprov.invia_messaggio(phoneNumber,messaggio);}
...
public class MockProvider extends Thread{private Context ctx; private SmsManager sms;
private PendingIntent sentPI; private PendingIntent deliveredPI;
...
@Override
public void run() {
sentPI = PendingIntent.getBroadcast(ctx, 0, new Intent(SENT), 0);
deliveredPI = PendingIntent.getBroadcast(ctx, 0, new Intent(DELIVERED), 0);
}
public void invia_messaggio(String PHNUM, String MEX){sms.sendTextMessage(PHNUM, null,MEX, sentPI, deliveredPI);}
}
User Interface Testing 53
Unit Testing di altri componenti
Per testare il ciclo di vita di un Service si possono utilizzare i metodi Context.startService e Context.bindService– Il testing di un servizio è più semplice del testing di una Activity, perchè non dipende da eventi utente e di sistema
Un Broadcast Receiver è molto semplice da testare. Per avviarlo da test si può utilizzare il metodo Context.sendBroadcast per simulare l’invio di un Intent
Un ContentProvider fornisce un’astrazione di accesso ai dati. Deve essere testato rispetto all’interfaccia di accesso che fornisce
Alcune apposite classi da cui ereditare– ServiceTestCase, ProviderTestCase2
User Interface Testing 54
Esempi di testing Android
• Alcuni esempi svolti di testing di applicazioni Android– http://code.google.com/p/testcacciaaltesoro/
– http://code.google.com/p/accelerometersensortesting/
– http://code.google.com/p/alarmservicetesting/
– http://code.google.com/p/brightnesssensortesting/
– http://code.google.com/p/compasssensortesting/
– http://code.google.com/p/giroscopioserviziotesting/
– http://code.google.com/p/pressuresensortesting/
– http://code.google.com/p/proximitysensortesting/
– http://code.google.com/p/smsservicetesting/
– http://code.google.com/p/temperaturesrvicetesting/
User Interface Testing 55
Livelli di Testing
Dopo lo Unit Testing:
– Integration Testing• Le varie unità sono testate in insiemi più grandi
– System Testing in tre stage• Simulation stage
– Il software viene testate in isolamento in un ambiente completamente simulato
• Prototyping stage
– L’ambiente reale inizia a rimpiazzare quello simulato, ma il software è eseguito sempre su di un emulatore
• Pre-production stage
– Il software è eseguito su di un device reale in un ambiente reale
User Interface Testing 56
DDMS
Il DDMS (Dalvik Debug Monitor Server) è uno strumento dell’Android SDK particolarmente utile in fase di prototyping
– Monitora il comportamento della macchina virtuale • Accesso al file system
• Thread in esecuzione
• Allocazione della memoria
• Log dei messaggi
– Consente l’emulazione (spoofing) di • Variazioni nelle coordinate GPS
• Ricezioni di messaggi SMS
• Ricezione di telefonate
User Interface Testing 57
DDMS
User Interface Testing 58
Robotium
Robotium è un framework a supporto del testing di unità delle Activity che estende e potenzia Junit. In particolare:– è più semplice scrivere test che riguardano piùActivity, Dialog, Toast, Menu e Context Menu.
– E’ migliorata la leggibilità dei test case
– I test case sono meno dipendenti dalla variabilità dei tempi di esecuzione
Robotium è un progetto open source la cuin prima versione è stata rilasciata a gennaio 2010– http://code.google.com/p/robotium/
User Interface Testing 59
Caratteristiche di Robotium
Il funzionamento di Robotium è tutto basato sull’utilizzo di un oggetto denominato SOLOSolo solo = new Solo(getInstrumentation(),getActivity());
Tramite l’oggetto solo è possibile interrogare e modificare i widget della UI, eventualmente anche senza conoscerne l’identificativo– Particolarmente utile nei test di accettazione
– Ad esempio, è possibile selezionare l’insieme dei widget visibili oppure è possibile selezionare un widget in base al testo che mostra
User Interface Testing 60
Esempi
public void testTextView(){
String resourceString = new String(solo.getString(com.porfirio.orariprocida2011.R.string.mezzo));
TextView mTextView1=solo.getText(1);
assertEquals(resourceString,(String)mTextView1.getText());
}
public void testButtonRobotium(){
TextView mTxtOrario=solo.getText(3);
String initial=new String(mTxtOrario.getText().toString());
solo.clickOnButton("<<");
solo.clickOnButton(">>");
assertEquals(mTxtOrario.getText().toString(),initial);
}
User Interface Testing 61
Monkey
Monkey è un’utility interna fornita con l’android SDK, che è in grado di generare eventi utente pseudocasuali su una qualsiasi interfaccia, registrando gli eventuali crash– Monkey gira all’interno del dispositivo; per avviarla bisogna passare per adb. Ad esempio, da linea di comando:adb shell monkey –v -p
com.porfirio.orariprocida2011 30
User Interface Testing 62
Output di Monkey
:Monkey: seed=0 count=30:AllowPackage: com.porfirio.orariprocida2011:IncludeCategory: android.intent.category.LAUNCHER:IncludeCategory: android.intent.category.MONKEY// Event percentages:// 0: 15.0%// 1: 10.0%// 2: 15.0%// 3: 25.0%// 4: 15.0%// 5: 2.0%// 6: 2.0%// 7: 1.0%// 8: 15.0%:Switch:
#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10000000;component=com.porfirio.orariprocida2011/.OrariProcida2011Activity;end
// Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.porfirio.orariprocida2011/.OrariProcida2011Activity } in package com.porfirio.orariprocida2011
:Sending Pointer ACTION_MOVE x=-4.0 y=2.0:Sending Pointer ACTION_UP x=0.0 y=0.0:Sending Pointer ACTION_DOWN x=47.0 y=122.0Events injected: 30:Dropped: keys=0 pointers=0 trackballs=0 flips=0## Network stats: elapsed time=7766ms (7766ms mobile, 0ms wifi, 0ms not connected)// Monkey finished
User Interface Testing 63
Monkeyrunner
Monkeyrunner, a differenza di monkey, è un API che consennta la scrittura di programmi in grado di controllare un dispositivo Android dall’esterno– Ad esempio è possibile scrivere un programma Python che installa un’applicazione, esegue casi di test, invia eventi, salva screenshot
Esempio di programma:from com.android.monkeyrunner import MonkeyRunner, MonkeyDevicedevice = MonkeyRunner.waitForConnection()device.installPackage('myproject/bin/MyApplication.apk')package = 'com.example.android.myapplication'activity = 'com.example.android.myapplication.MainActivity'runComponent = package + '/' + activitydevice.startActivity(component=runComponent)device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP)result = device.takeSnapshot()result.writeToFile('myproject/shot1.png','png')
User Interface Testing 64
Android Crawler
Una alternativa, con più “intelligenza” di Monkey è l’Android Crawler sviluppato all’Università di Napoli– Navigazione “in ampiezza” dell’interfaccia utente di un’applicazione Android
• Esecuzione di eventi su tutti i Widget trovati
– Generazione di sequenze di esecuzione
– Generazione di casi di test JUnit
– Rilevazione automatica di crash
– Valutazione della copertura ottenuta (con Emma)
User Interface Testing 65
Problemi
L’albero èteoricamente illimitato Si può limitarlo:– fissando un limite alla profondità
– interrompendo l’esplorazione quando si giunge ad una Activity “simile” ad una già esplorata
User Interface Testing 66
Emma
Emma è uno strumento di istrumentazione del codice sorgente che consente di valutare l’effettiva copertura del codice ottenuta a seguito dell’esecuzione di un insieme di casi di test
Può essere eseguito solo da linea di comando, tramite adb. Ad esempio:– adb shell am instrument -w -e coverage true [Package di test]/android.test.InstrumentationTestRunner
Genera report e metriche, anche in formato HTML
Molto utile per il testing White Box
User Interface Testing 67
Output di EMMA
User Interface Testing 68
Copertura del codice con EMMA
User Interface Testing 69
Altri processi di testing
Performance testing
Stress testing
Security Testing
Compatibility Testing
Usability Testing
Accessibility Testing
User Interface Testing 70
Appendice:
Analisi delle vulnerabilità di applicativi web-based e studio delle contromisure
User Interface Testing 71
Sql injection
Tecnica volta a sfruttare cattive implementazioni al fine di creare query “maligne”
Inserisco :
Login qualsiasi
Password 1' or '1' = '1
User Interface Testing 72
Studio query
ResultSet rs = statement.executeQuery("SELECT * FROM operatore2 " +"WHERE login_op='" +login+ "' AND " +"password_op='" +pass+ "'");
Query risultante dalla sostituzione dei parametri
SELECT * FROM operatore2 WHERE login_op='qualsiasi' AND password_op='1' or '1' = '1‘.
Il confronto 1=1 è sempre vero ed è per questo che come risultato avremo tutte i record del database.
User Interface Testing 73
Rimedi Sql injection
Utilizzo dei prepared statementPreparedStatement stmt= conn.prepareStatement
("SELECT * FROM operatoremd5 WHERE login_op= ? AND password_op= ?");
stmt.setString(1,login);
stmt.setString(2,password);
ResultSet rs= stmt.executeQuery();
Parametrizazione dei dati
Evitata la concatenazione di stringhe
Più efficienza nel caso di una stessa query richiamata con parametri diversi
User Interface Testing 74
Validazione degli inputIl tipo di dato (string, integer, real, etc…)Il set di caratteri consentito La lunghezza minima e massima dei caratteri Controllare se è permesso il tipo NULL Controllare se il parametro è richiesto o menoIntervallo numerico
Esempi di codice per i controlliLunghezzaif(login.length()>15 || pass.length()>15)
Campi vuotiif (pass.length()==0 || login.length()==0)
Tipo di datoBlocco try{ }catch (NumberFormatException e){codice per la gestione}
Generazione null point exceptionBlocco try{ } catch (NullPointerException e){codice per la gestione}Nel caso uno di questi controlli non fosse rispettato l’utente deve essere
informato da un messaggio di errore
User Interface Testing 75
Insecure Storage
Codifica dei dati per renderli illeggibiliAlgoritmi:Md5 RsaMd5Non è invertibileGenerazione di Stringhe univoche a partire dall’input.
Non crea ambiguità
User Interface Testing 76
Escalation di permessiSi tenta di accedere a funzionalità non autorizzate al ruolo.Nella prima
figura un semplice utente pùo relizzzare solo la funzione di visualizzazione profili.Nella seconda l’amministratore ha a disposizione anche quella di eliminazione.
Dati inviati da un semplice utente per realizzare la funzione di visualizzazione
Dati inviati dall’amministratore per realizzare la funzione di visualizzazione
User Interface Testing 77
Studio della pagina funzioni.jsp
int opr = Integer.parseInt(request.getParameter("ruoloOp"));
botton1 = request.getParameter("visProfilo");
if(botton1!=null){
if (botton1.equalsIgnoreCase("Visualizza profilo") && opr == 3) {
//codice per effettuare la funzione visualizza profilo //}
String del = request.getParameter("elimina");
else if (del.equalsIgnoreCase("elimina profilo") && (opr == 3)) {//
codice per l’eliminazione utente //}
Recupero dei dati mostrati in precedenza per conoscere la scelta selezionata
Controllo del ruolo dell’utente che richiede la funzionalità, effettuato mediante un hidden field
Esecuzione della funzionalità prescelta
User Interface Testing 78
Esecuzione dell’escalation di permessi
Da utente normali richiesta della funzione di visualizzazione sull’utente valentino
Intercettiamo i dati con Web Scarab
1) Modifica del ruolo utente
2) Modifica del tipo della seconda coppia di Variabili Valore
� Notifica di avvenuta eliminazione confermata dalla stampa degli utenti ancora presenti nell’applicativo.
User Interface Testing 79
Gestione corretta delle funzioni
Recupero del ruolo utente memorizzato ,in fase di autenticazione,nell’oggetto session (lato server)
ruoloop=((beans.Operatore)session.getAttribute("operatore")).getRuolo();Aggiunta di un controllo che appura l’utente che sta richiedendo la specifica funzione.if(vis.equalsIgnoreCase("Visualizza profilo") &&
db.èautorizzato(ruoloop,"Visualizza profilo")) { codice per eseguire la funzione visualizza }
if(elimina.equalsIgnoreCase("Elimina operatore")&& db.èautorizzato(ruoloop,"Elimina operatore")){codice per eseguire la funzione elimina }
La funzione èautorizzato in base al ruolo dell’utente e al tipo di funzione da eseguire restituisce l’atorizzazione a processarla.Il codice è il seguente:
public boolean èautorizzato(int ruoll,String funzione){if(funzione.equalsIgnoreCase("Elimina operatore")) return (ruoll==3);if(funzione.equalsIgnoreCase("Visualizza profilo")) return true;else return false;}Provando ora a richiedere la funzione di eliminazione da semplici utenti
User Interface Testing 80
Accesso a pagine riservate
Non prevedendo meccanismi di controllo chiunque può accedere ad una pagina anche se non consentito dal ruolo.
Sicurezza basata sul Security through Obscurity
User Interface Testing 81
Corretta policy di accesso alle pagine
Ad ogni pagina viene associato un livello di protezioneViene richiamata una funzione che verifica se l’utente possiede i
permessi per fruire della pagina.Nel caso non si possiedono i permessi si viene rimandati alla
pagina principale con un messaggio di errore
User Interface Testing 82
XSS Cross-site scripting
Immissione di codice javaScript non opportunamente filtrato allo
scopo di sottrare dati sensibili agli utenti (cookie,password..)
Stored:codice immesso rimane in maniera permanente nell’applicativo es. immissione come post di un blog
Reflected:codice è valido solo per una richiesta specifica es.inserimento in un campo di ricerca
XSS
User Interface Testing 83
Simulazione stored xss
•Immissione nel campo mail del codice:
<script>alert("Il tuo session ID è stato rubato ed è:"+document.cookie)</script>
•Il codice ruba il session id di chi visualizza il profilo “maligno”
User Interface Testing 84
Simulazione stored xss
L’amministratore una volta loggato visualizza il nuovo profilo L’utente “hacker” riceve il session id dell’amministratore
User Interface Testing 85
Simulazione stored xss
Recuperato il session id l’utente effettua una richiesta ad una pagina accessibile solo all’amministratore modificando il suo header
� Verremo riconosciuti come amministratori potendo accedere a tutte le funzionalità
User Interface Testing 86
Rimedi contro l’Xss
Codifica dei dati in html in particolare dei caratteri specialiMetodo encode della classe HtmlEncoderIl codice immesso risulterà:
<script>alert("Il tuo session ID è stato rubato ed è:"+document.cookie)</script>
Il browser non interpreterà più il codice come JavaScript ma come semplice testo rendendolo innocuo
User Interface Testing 87
Conclusioni
Alcuni principi da seguire per garantire la sicurezza:
Principio del Secure by default (password complesse ,rinnovo periodico)Principio del Least PrivilegePrincipio del Defense in depthConsiderare i sistemi esterni come insicuriNon fidarsi del “ Security through Obscurity ”Prendere le giuste contromisureConsiderare la sicurezza come un processo e trattarlo come tale. Esso deve
partire già dalla fase di progettazione nonchè prevedere opportuni penetration testing