Software Testing
User Interface Testing
User Interface Testing
1
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
2
Testing di sistemi interattivi
• Il testing di sistemi interattivi (in particolare di interfacce
utente) viene condotto tipicamente in maniera black box
• Tipicamente i casi di test sono progettati tenendo in conto
le possibili interazioni che un utente può eseguire
sull’interfaccia utente
– Per poter approcciare il problema del testing è fondamentale la
disponibilità di un modello descrittivo delle interazioni utentemacchina
– Quali modelli sono utilizzabili per modellare UI?
User Interface Testing
3
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 alcuna
operazione se non in seguito a sollecitazioni da parte degli
utenti
– Lo “stato” dell’interfaccia utente viene modellato da uno stato di un
automa
– L’esecuzione di eventi sulla UI (es. Click su button…) viene
modellata come ingressi impulsivi che scatenano transizioni
nell’automa
– Gli input immessi sono modellati come ingressi a livelli da cui
dipende la transizione che si verifica
User Interface Testing
4
Esempio- modello di FSM per una UI
Click on "Add new film"
Click on
"Search"
Se arch Movie
Click on
"Search"
Logged As Admin
Click on "Cancel"
Click on
"Back"
List of Films
Click on
"film's link"
Click on
"Cancel"
Click on
"OK"
Click on
"film's link"
Film Information
Click on
"Back"
Click on
"Insert"
Click on
"Cancel"
Film
Information +
list of film
Click on
"Back"
Movie Inserted
Film Information
+ Search Movie
Es.: L’FSM che descrive l’evoluzione di una UI per l’ esecuzione di un Caso d’Uso
User Interface Testing
5
Testing delle interfacce
• Gli input dei casi di test devono essere indicati sotto
forma di sequenze di valori di input ed eventi da
eseguire.
– A seconda dei criteri di copertura (es. Stati, Eventi, Transizioni,
path…), si progetteranno diversi TC
– Es.: click (add-film),click(search), click(film
link),click(insert), click(OK) è il TC che permette di
eseguire il cammino in rosso (Scenario: Inserimento Film OK)
• Ad una sequenza di valori di input dovrebbe
corrispondere una sequenza di stati visitati e di
output riscontrati.
User Interface Testing
6
Esempio- modello di FSM per una UI
Click on "Add new film"
Click on
"Search"
Se arch Movie
Click on
"Search"
Logged As Admin
Click on "Cancel"
Click on
"Back"
List of Films
Click on
"film's link"
Click on
"Cancel"
Click on
"OK"
Click on
"film's link"
Film Information
Click on
"Back"
Click on
"Insert"
Click on
"Cancel"
Film
Information +
list of film
Click on
"Back"
Movie Inserted
Film Information
+ Search Movie
Es.: Cammino di esecuzione che esercita un certo scenario del Caso d’Uso
User Interface Testing
7
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 Rich
Internet 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
8
Esempio in Java
public JMenu createOptionMenu()
{
JMenu m = new JMenu("Scientifica");
JMenuItem item = new JMenuItem();
Menu generato a run time
Voce di Menu generata a run time
class itemListener implements ActionListener
Ascoltatore dichiarato a run time
{
public void actionPerformed(ActionEvent e)
Codice dell’ascoltatore dichiarato a run time
{
try{
op1 = Double.parseDouble(text.getText());
}
catch(NumberFormatException ecc)
{
text.setText("Errore: nessun valore inserito!");
return;
}
operazione = RADICE_QUADRATA;
invio.doClick();
}
}
…
}
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
9
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
10
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
11
Automatizzazione
• Per poter eseguire automaticamente casi di test
su interfacce utente sono necessari:
– Strumenti che consentano di emulare il comportamento
dell’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
12
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
Selenium
Selenium
Selenium
IDE
Core
Remote Control
Grid
User Interface Testing
13
Selenium IDE
• Si tratta di un’estensione di un browser che
consente 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 degli
esiti dei test (fase di Replay)
• Selenium è dunque usabile per progettare TC anche a
prescindere da un modello formalizzato (es. FSM) della
UI.
• Utile per l’esecuzione di Testing di Accettazione
User Interface Testing
14
Capture
In fase di capture,
Selenium IDE
mantiene un log
delle operazioni
effettuate
dall’utente e delle
asserzioni da egli
proposte
User Interface Testing
15
Replay
In fase di replay,
Selenium IDE esegue
automaticamente test
generati in fase di
capture, mantenendo
statistiche sul numero
di test terminati con
successo e falliti
User Interface Testing
16
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ò essere
eseguito
indipendentemente da
Selenium IDE
Il codice generato necessita,
per essere eseguito, di
packages forniti con
Selenium (che formano il
Selenium Core)
User Interface Testing
17
"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
18
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
19
Il problema della validazione degli 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
20
Esempio: Cross-Site Scripting
Si verifica quando uno script lato client, inserito maliziosamente in un
campo di input, viene eseguito sulla macchina client di un utente ignaro
Guestbook.asp
Sign.html
<% conn=OpenDBConnection
rs=server.createobject("Adodb.recordset")
rs.open "SELECT Message FROM GuestBook" ,
conn,3,3
%>
Message=Server.HtmlEncode(Message) <table>
<% rs.movefirst
while not(rs.eof)
Sign.asp
response.write (rs.fields("Message"))
<% Message=request.form("txtMessage")
rs.movenext
conn=OpenDBConnection
wend
set rs=server.createobject("Adodb.recordset") %>
rs.open "Guestbook",conn,1,2,2
</table>
rs.Addnew
<% rs.close
rs("Message")=Message
set rs=nothing
rs.update
conn.close
%>
set conn=nothing
%>
<form method="post" action="sign.asp">
<textarea name="txtMessage"></textarea>
<input type="submit" value="Sign!">
</form>
User Interface Testing
21
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 runtime, 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
22
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/javatutorials/25923-robot-class.html
User Interface Testing
23
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
24
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
25
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
26
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
27
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
28
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
29
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
30
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
31
Uno scenario di utilizzo di Costello
•
Creazione di un nuovo caso
di test
1. File/New Script:
2. Imposta classe e metodo di
partenza e posizione del jar
3. Cattura/All Actions
4. 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’asserzione
7. Termina
8. File/Save (in formato XML)
User Interface Testing
32
Uno scenario di utilizzo di Costello
•
Esecuzione
di un caso
di test
1. File/New
Script
2. Seleziona
una test
suite
3. Esegui
4. Verifica
l’esito delle
asserzioni
User Interface Testing
33
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
34
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
35
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
36
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
37
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
38
Android Test Architecture
User Interface Testing
39
Creazione di un progetto di test
Da linea di comando si può scrivere
android create test-project -m <main_path> -n <project_name>
-p <test_path>
In Eclipse è sufficiente utilizzare il widget di
creazione progetto
User Interface Testing
40
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" />
Controlla
l’esecuzione delle
classi del package
<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>
User Interface Testing
41
Creazione di una classe di test
Utilizzo di
JUnit3
User Interface Testing
42
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
43
Primi test case
Precondizioni: esistenza degli oggetti utilizzati nel test
…
public class
OrariProcida2011ActivityTests
extends
ActivityInstrumentationTestCase2<OrariPr
ocida2011Activity> {
private OrariProcida2011Activity
mActivity;
private TextView mTextView1;
private ListView mListView;
public void testPreconditions() {
assertNotNull(mTextView1);
assertNotNull(mListView);
}
public void testTextView1(){
String resourceString = new
String(mActivity.getString(com.porfir
io.orariprocida2011.R.string.mezzo));
@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)
;
assertEquals(resourceString,(String)mTextView1.
getText());
}
protected void tearDown() throws Exception
{
super.tearDown();
}
}
}
Oggetti utilizzati nel test
Test sul corretto valore di una casella di testo
User Interface Testing
44
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
45
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
46
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
47
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
48
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
49
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
50
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
<<Activity>>
SMSActivity
<<Broadcast Receiver>>
SMSReceiver
+onCreate()
+onReceive()
<<Thread>>
MockProvider
SMSMock
+onCreate()
1
+sendMessage()
1
SMSTesting
+test()
User Interface Testing
51
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
52
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
53
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
54
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
55
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
56
DDMS
User Interface Testing
57
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
58
Caratteristiche di Robotium
Il funzionamento di Robotium è tutto basato
sull’utilizzo di un oggetto denominato SOLO
Solo 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
59
Esempi
public void testTextView(){
String resourceString = new
String(solo.getString(com.porfirio.orariprocida2011.R.string.me
zzo));
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
60
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
61
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.0
Events injected: 30
:Dropped: keys=0 pointers=0 trackballs=0 flips=0
## Network stats: elapsed time=7766ms (7766ms mobile, 0ms wifi, 0ms not connecte
d)
// Monkey finished
User Interface Testing
62
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,
MonkeyDevice
device = MonkeyRunner.waitForConnection()
device.installPackage('myproject/bin/MyApplication.apk')
package = 'com.example.android.myapplication'
activity = 'com.example.android.myapplication.MainActivity'
runComponent = package + '/' + activity
device.startActivity(component=runComponent)
device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP)
result = device.takeSnapshot()
result.writeToFile('myproject/shot1.png','png')
User Interface Testing
63
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
64
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
65
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
66
Output di EMMA
User Interface Testing
67
Copertura del codice con EMMA
User Interface Testing
68
Altri processi di testing
Performance testing
Stress testing
Security Testing
Compatibility Testing
Usability Testing
Accessibility Testing
User Interface Testing
69
Appendice:
Analisi delle vulnerabilità di applicativi webbased e studio delle contromisure
User Interface Testing
70
Sql injection
Tecnica volta a sfruttare cattive implementazioni al fine di creare query
“maligne”
Inserisco :
Login
Password
qualsiasi
1' or '1' = '1
User Interface Testing
71
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
72
Rimedi Sql injection
Utilizzo dei prepared statement
PreparedStatement 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
73
Validazione degli input
Il 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 meno
Intervallo numerico
Esempi di codice per i controlli
Lunghezza
if(login.length()>15 || pass.length()>15)
Campi vuoti
if (pass.length()==0 || login.length()==0)
Tipo di dato
Blocco try{ }
catch (NumberFormatException e){codice per la gestione}
Generazione null point exception
Blocco 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
74
Insecure Storage
Codifica dei dati per renderli illeggibili
Algoritmi:
Md5
Rsa
Md5
Non è invertibile
Generazione di Stringhe univoche a partire dall’input.
Non crea ambiguità
User Interface Testing
75
Escalation di permessi
Si 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
76
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
77
Esecuzione dell’escalation di permessi
Da utente normali richiesta della funzione di visualizzazione sull’utente
valentino
Intercettiamo i dati con Web Scarab
1)
2)
Modifica del ruolo utente
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
78
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
79
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
80
Corretta policy di accesso alle pagine
Ad ogni pagina viene associato un livello di protezione
Viene 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
81
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
XSS
Reflected:codice è valido solo per una richiesta specifica
es.inserimento in un campo di ricerca
User Interface Testing
82
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
83
Simulazione stored xss
L’amministratore una volta loggato visualizza il nuovo profilo
L’utente “hacker” riceve il session id dell’amministratore
User Interface Testing
84
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
85
Rimedi contro l’Xss
Codifica dei dati in html in particolare dei caratteri speciali
Metodo encode della classe HtmlEncoder
Il codice immesso risulterà:
&lt;script&gt;alert(&quot;Il tuo session ID &egrave; stato rubato ed
&egrave;:&quot;+document.cookie)&lt;/script&gt;
Il browser non interpreterà più il codice come JavaScript ma come
semplice testo rendendolo innocuo
User Interface Testing
86
Conclusioni
Alcuni principi da seguire per garantire la sicurezza:
Principio del Secure by default (password complesse ,rinnovo periodico)
Principio del Least Privilege
Principio del Defense in depth
Considerare i sistemi esterni come insicuri
Non fidarsi del “ Security through Obscurity ”
Prendere le giuste contromisure
Considerare la sicurezza come un processo e trattarlo come tale. Esso deve
partire già dalla fase di progettazione nonchè prevedere opportuni
penetration testing
User Interface Testing
87
Scarica

16-User Interface Testing2012