Introduzione ai Mocking Framework (Android)

Nel testing del software, specialmente nel testing di unità, è molto frequente che un tester ha bisogno di testare una classe o solo un metodo della classe, senza avere a disposizione le varie dipendenze per quella classe o metodo. I motivi per i quali non si hanno disponibili le dipendenze sono dovuti al mancato completamento di quella dipendenza durante lo sviluppo del software, un alto costo nell'invocare quella dipendenza (e.g. web service di terze parti, rete lenta, database), e anche la potenziale interferenza dei bug delle dipendenze nel nostro test di unità.

A questo punto ci vengono in aiuto i Mock Object che nel testing di unità, e soprattutto nel testing in isolamento, ci permettono di simulare in modo controllato un oggetto reale. Per fare ciò esistono metodi più “artigianali” come ad esempio estrarre un’interfaccia rispetto alla dipendenza da sostituire e far implementare i metodi ad una classe “finta” (Mock). Mentre se vogliamo creare un Mock parziale della classe, la possiamo estendere e fare i Mock solo dei metodi che ci interessano. Poi in entrambi i casi dobbiamo iniettare il Mock durante il testing.

Un’altra strada è quella di utilizzare un framework che permette di fare le operazioni espresse sopra in maniera più comoda e veloce. In Java esistono diversi framework come: EasyMock, JMock, Mockito, PowerMock, ecc.

Analizzeremo questi framework in generale, ma in un prossimo post verranno analizzati più nel dettaglio i Mock in Android, quindi in questo post ci sono dei riferimenti al testing in Android.

Sappiamo bene che il linguaggio utilizzato per programmare Android è Java e quindi possiamo usare uno dei framework precedentemente citati. In questo post verranno analizzati Mockito e PowerMock.

L’uso dei Mocking framework

Come accennato in precedenza esistono diversi framework per utilizzare i mock. Potrebbe risultare interessante conoscere il framework più usato, in che modo i tester utilizzano questi framework, e altro ancora. Molte di queste domande vengono empiricamente risposte nella pubblicazione “An Empirical Study on the Usage of Mocking Frameworks in Software Testing” di Shaikh Mostafa, Xiaoyin Wang. Ci sono anche ulteriori riflessioni su questi framework. Al momento non riporto ulteriori informazioni poiché è materiale IEEE per il quale va richiesto il consenso.

In generale Mockito è veramente molto diffuso.

User Interface Test e Unit Test

Esistono diverse classificazioni dei test, ma in particolare nei software con interfaccia grafica, come ad esempio le applicazioni Android, il test della GUI si ritiene spesso un’attività fondamentale.
Nel prossimo post, relativo ai Mock in Android, ci concentreremo sul test di unità combinato all'uso dei mock, proprio per questo motivo vengono sinteticamente riportate le differenze rispetto all’User Interface Testing
valutando diversi punti di vista. Notiamo che per sviluppare codice di qualità nessuno dei due approcci dovrebbe sostituire l’altro, ma dovrebbero essere complementari, anzi combinati ancora con altri tipi di testing.

UI Test e Unit Test (Piramide)

I test dell’interfaccia utente, ad esempio su app Android, sono lanciati sull’emulatore oppure sul dispositivo fisico. Questo richiede maggiore tempo di esecuzione dei test e anche di maggiori risorse computazionali se ad esempio lanciamo più Monkey test in parallelo sulle GUI. Però possiamo fare testing di sistema guidato dalla GUI, ad esempio su un dispositivo o emulatore. Quest’ultimi potrebbero essere più rilevanti per il committente. Alcuni difetti potremmo scoprirli solo eseguendo l’applicazione e facendo generare codice dinamico relativo alla GUI.

Rifacendoci a quanto mostrato in figura, quando fallisce uno dei test non è immediatamente chiaro dove risiede il problema, dato che il test potrebbe potenzialmente utilizzare l’intero sistema e quindi l’errore potrebbe essere ovunque nell’applicazione e non necessariamente nell’interfaccia.

Testando la GUI è molto difficile raggiungere le parti più remote di un software, cosa che invece riesce a fare benissimo il test di unità che appunto si focalizza su un singolo metodo. Ovviamente per raggiungere questo obiettivo bisognerà sviluppare test di unità per ogni metodo e/o classe. Questo porta ad un numero maggiore di test rispetto ai test della GUI, come evidenziato alla base della fig. UI Test e Unit Test (Piramide).

Unit Test in Android

Il testing di unità in Android può essere effettuato in due modi:

  • Local Unit Test: Il test è compilato per eseguire sulla Java Virtual Machine (JVM) locale e questo minimizza il tempo di esecuzione. Il test di unità eseguito in questo modo non deve avere dipendenze con l’Android framework oppure per queste dipendenze dobbiamo usare i Mock Object.
  • Istrumented tests: Questo test di unità esegue sul dispositivo fisico o sull’emulatore. In questo caso possiamo avere accesso alle “instrumentation information”, come ad esempio il Context. Questo è un approccio da usare se ad esempio è difficile creare i mock per le dipendenze del framework Android.

Local Unit test

I test di unità in locale sono un approccio più efficiente, perché evitano l’overhead di caricare l’app target e il codice di test nell’emulatore o il dispositivo fisico. Questo porta ad una riduzione del tempo necessario al test di unità.
I test di unità sono eseguiti su una versione modificata della libreria Android.jar , che non contiene il vero codice android. Questo ci assicura che testiamo solo il nostro codice, quindi che non dipende dal particolare comportamento della piattaforma android. Per essere sicuri che testiamo solo il nostro codice, quando usiamo la versione modificata di Android.jar, qualsiasi metodo che usa una API di Android causa eccezione (nel caso in cui non abbiamo creato un Mock per questa dipendenza).

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.