2015-04-14 5 views
10

Sto provando a creare un test con Robolectric. Il mio obiettivo è di essere in grado di sostituire la funzionalità di una classe (che viene ad esempio da una libreria e non posso modificare il codice) da un comportamento personalizzato.Robolectric shadow non funziona

Ho creato questo piccolo test per simulare quello che voglio fare:

@RunWith(RobolectricTestRunner.class) 
@Config(shadows = {ShadowMessenger.class}) 
public class TestShadow { 

    @Test 
    public void testMessenger() { 
     OriginalMessenger messenger = new OriginalMessenger(); 
     String message = messenger.getMessage(); 
     Assert.assertEquals("Shadow messenger", message); 
    } 

    public static class OriginalMessenger { 

     public String getMessage() { 
      return "Original messenger"; 
     } 
    } 

    @Implements(OriginalMessenger.class) 
    public static class ShadowMessenger extends OriginalMessenger { 

     @Implementation 
     public String getMessage() { 
      return "Shadow messenger"; 
     } 
    } 
} 

Nell'esempio, OriginalMessenger è la classe che si trova nella libreria e fornisce una funzionalità predefinita. E ShadowMessenger è la classe che contiene il comportamento personalizzato che voglio applicare ogni volta che utilizzo OriginalMessenger.

Tuttavia quando eseguo il test fallisce. Il contenuto del messaggio è "Messenger originale". Come se lo ShadowMessenger non fosse mai usato.

Cosa sto sbagliando?

+2

Perché fare un'ombra? Perché non 'mock' o' stub' it out? –

+0

Come ottengo lo stesso risultato usando mock e stub? –

+0

Oh, vedo nenick ha risolto il tuo problema? Puoi usare EasyMock/PowerMock per deridere la tua classe o Spock (Robospock). Guarda un esempio qui: https://github.com/jaredsburrows/BurrowsAppsExamples/blob/master/Lib-BurrowsApps/src/test/java/burrows/apps/example/lib/utils/PlayServicesUtilsTest.java. –

risposta

14

Originale è possibile solo shadow classi Android. Con un corridore di prova robolectric personalizzato puoi anche mettere in ombra le tue classi.

Robolectric 3.1.4 (RobolectricGradleTestRunner era completamente rimosso, quindi è necessario eseguire l'override metodo descritto di seguito in RobolectricTestRunner)

@Override 
protected ShadowMap createShadowMap() { 
    return new ShadowMap.Builder() 
     .addShadowClass(OriginalMessenger.class, ShadowMessenger.class, true, true, true) 
     .build(); 
} 

Robolectric 3,0

@Override 
public InstrumentationConfiguration createClassLoaderConfig() { 
    InstrumentationConfiguration.Builder builder = InstrumentationConfiguration.newBuilder(); 
    builder.addInstrumentedClass(OriginalMessenger.class.getName()); 
    return builder.build(); 
} 

Robolectric 2,4

@Override 
protected ClassLoader createRobolectricClassLoader(Setup setup, SdkConfig sdkConfig) { 
    return super.createRobolectricClassLoader(new ExtraShadows(setup), sdkConfig); 
} 

class ExtraShadows extends Setup { 
    private Setup setup; 

    public ExtraShadows(Setup setup) { 
     this.setup = setup; 
    } 

    public boolean shouldInstrument(ClassInfo classInfo) { 
     boolean shoudInstrument = setup.shouldInstrument(classInfo); 
     return shoudInstrument 
       || classInfo.getName().equals(OriginalMessenger.class.getName()); 
    } 
} 

esempio di progetto https://github.com/nenick/android-gradle-template/

+0

Bello! Non lo sapevo –

+5

Ci sono molte funzionalità non documentate;) – nenick

+0

Se lo faccio ottengo un StackOverflowError. Sai perché succede? –