2011-09-12 11 views
11

Sto scrivendo alcuni test POJO per il mio codice Android.Test del codice Android con JUnit e JDK

Voglio eseguirli localmente con il JDK (non con Dalvik sull'emulatore) - per velocità, JUnit 4, Mockito, e poter girare senza headless senza un dispositivo - quindi ho un progetto "Java" separato in Eclisse.

Se il metodo che sto testando fa riferimento a qualsiasi cosa proveniente dall'SDK di Android, ad es. android.util.Log, il test ha esito negativo - questo ha senso perché android.jar non si trova nel classpath. Per riprodurre Ho questo banco di prova:

public class FooTests { 
    @Test 
    public void testFoo() { 
    android.util.Log.d("x", "y"); 
    } 
} 

Se aggiungo android.jar esplicitamente al classpath del progetto di test, ho eccezioni come

java.lang.RuntimeException: Stub! 
    at android.util.Log.d(Log.java:7) 
    at com.example.FooTests.testFoo(FooTests.java:39) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    ... 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 

c'è un modo per rendere il codice di lavoro senza beffardo fuori ogni ultimo bit della dipendenza da Android SDK? Forse uno stordito android.jar esiste già?

EDIT: Per ora ho finito per il confezionamento classi come android.util.Log e iniettare le istanze, per il test classico IOC-based. Il suggerimento di Scott PowerMock è il mio prossimo passo quando ne avrò bisogno.

LATER EDIT: Robolectric!

risposta

3

Non c'è un mocking fuori android.jar che io conosca. Uso Powermock per deridere tutto. Una cosa che puoi fare per aiutare il pesante beffeggiamento è quella di rendere magre le tue lezioni prolungate su Android come attività, frammenti, emittenti, ecc. E delegarle alle classi pojo. Potresti prendere una decisione basata sul rischio, non sull'unità di isolamento, testare le classi estese di Android, e invece l'unità di integrazione testarle tramite il framework di test di Android o qualcos'altro come Robotium.

Per i veri test delle unità di isolamento in Android, per me il test delle unità su java jvm mocking tutte le classi collaborative è la soluzione migliore.

+1

+1 Buoni punti, proverò PowerMock. Qualsiasi link pertinente oltre https://sites.google.com/site/androiddevtesting/? – orip

+1

Non ho visto quel collegamento prima, ma è eccellente, grazie per la condivisione. Mi trovo spesso a riferire la sezione "utilizzo" di Powermock sul loro sito web quando si cerca di capire i vari modi necessari per deridere le classi di jar Android: http://code.google.com/p/ powermock /. – Scott

0

Non lo farà fare quello che vuoi?

+4

Finora l'ho usato per eseguire test con InstrumentationTestRunner su un emulatore o su un dispositivo reale. È appropriato quando voglio testare un'attività o un servizio, ma non quando voglio semplicemente testare una semplice vecchia logica non correlata alla piattaforma Android. Mi sto perdendo qualcosa? – orip

+0

Penso che la prima pallottola parli di 'plain old junit' testing, per la tua 'semplice vecchia logica' :) – KevinDTimm

+0

Certo, ma per quanto posso dire che devo eseguirli su un emulatore o dispositivo, o ottenere "Stub" !" eccezioni come ora :( – orip

4

Ho avuto lo stesso problema. Volevo testare semplici POJO localmente.
In particolare, il mio codice voleva utilizzare android.util.Base64.
Quello che ho finito è stato utilizzare l'SDK per installare i sorgenti di Android 4 e copiare la classe android.util.Base64 nel mio progetto.
Sorprendentemente, questo ha funzionato.

+0

Sì, ho finito per creare un'interfaccia di tipo "Base64Encoder", implementandola con 'android.util.Base64' nell'app e con' sun.misc.BASE64Decoder' nei test :) Sarebbe stato fantastico per avere semplicemente un JAR con tutto il codice della libreria intatto, e solo i bit del framework che sono legati a un ambiente in esecuzione stoppato. – orip

2

Ho avuto lo stesso problema. Volevo testare la semplice logica di business localmente. In particolare, il mio codice utilizza android.util.SparseArray<E>.

Ho provato 3 diversi approcci per renderlo testabile con junit all'esterno di Android.

  • Nella mia logica di business ho creato un'interfaccia e attaccato a MySparseArray<E> che eredita da SparseArray<E>. Nel junit-test ho implementato nuovamente l'interfaccia usando HashMap<Integer, E>. Questo funziona, ma a lungo termine questo è molto lavoro per rendere la business logic testabile se sono richiesti altri android.*.
  • Come suggerito da @Tal Weiss ho aggiunto le origini java Android delle classi richieste: android.util.SparseArray.java che utilizza com.android.internal.util.ArrayUtils.java. Funziona anche, ma non mi piace aggiungere altre fonti Android, specialmente se ci sono molte più dipendenze
  • Ho scaricato uno stub free binary android.jar per un vecchio Android 2.2 da http://grepcode.com/snapshot/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1 e lo ho incluso come lib nella mia junit-java -progetto. Questo jar contiene solo classi per gli spazi dei nomi android.*, com.android.*, dalvik.* e framework.base.*. Anche questo funziona.

Attualmente mi riuscita a evitare l'uso di android.* classi tranne SparseArray<E> nel mio livello di business e non ha alcuna dipendenza Context, attività o servizio. Avrei potuto usare HashMap<Integer, E> nel livello business-android anziché SparseArray<E>.

+0

Ho provato https://github.com/bjoernQ/unmock-plugin per utilizzare SparseArray nei test di JUnit e ha funzionato, ma dopo aver aggiunto keepStartingWith "dalvik.system." nella sezione unMock. – Alexey