2011-08-30 9 views

Odpowiedz

11

Krótka odpowiedź brzmi: nie.

Robolectric jest selektywny na temat klas, które przechwytuje i instrumentów. W chwili pisania tego tekstu, tylko klasy, które będą być wyposażone w aparaturę musi mieć pełną classname meczu jeden z tych selektorów:

android.* 
com.google.android.maps.* 
org.apache.http.impl.client.DefaultRequestDirector 

Cały powodem istnienia Robolectric jest to, że zajęcia przewidziane w rzucie słoik Android SDK wyjątki po wywołaniu w JVM (tj. nie na emulatorze lub urządzeniu). Aktywność Twojej aplikacji ma źródło, które nie jest "wrogie" (prawdopodobnie nie generuje wyjątków, gdy wywoływane są metody lub konstruktory). Celem Robolectric jest umożliwienie testowania kodu aplikacji, co w innym przypadku byłoby niemożliwe ze względu na sposób, w jaki jest zapisywany SDK. Niektóre inne powody, dla których Robolectric został stworzony, to:

  • Zestaw SDK nie zawsze zawiera metody, które pozwalałyby na zapytanie o stan obiektów Android manipulowanych przez kod aplikacji. Cienie można zapisać, aby zapewnić dostęp do tego stanu.
  • Wiele klas i metod w Android SDK są ostateczne i/lub prywatne lub chronione, co utrudnia tworzenie zależności potrzebnych kodzie aplikacji, które w przeciwnym razie byłyby dostępne do kodu aplikacji.

Kod można wyraźnie zmienić na cień dowolnej klasy. Mówiono w przeszłości o wyodrębnieniu cech shadowing do samodzielnego bibliotece, aby pomóc pisanie testów za pomocą innego testu wrogie API.

Dlaczego chcesz śledzić swoją aktywność?

+0

Dziękuję za wyjaśnienie. Powodem, dla którego chcę śledzić moją aktywność, jest to, że została uruchomiona przez moją aplikację z wywołaniem funkcji "startActivityForResult (..)". Mam ten kod: 'ShadowActivity shadowActivity = shadowOf (activityA); \t Intent startedIntent = shadowActivity.getNextStartedActivity(); \t \t ShadowIntent shadowIntent = shadowOf (startedIntent); \t assertThat (shadowIntent.getComponent(). GetClassName(), equalTo (activityB.class.getName())); 'Chcę uzyskać widoki z activityB. Używając natywnego API, użyłem 'ActivityMonitora' ale chcę wiedzieć, jak to zrobić za pomocą Robolectric. – kaneda

2

jako aktualizacja, byłem w stanie stworzyć cienie moich własnych klas, tak długo jak jestem ostrożny, aby związać klasę cień przed ewentualna ładowarka działa w tej klasie. Tak więc, zgodnie z instrukcją, w RoboRunner zrobiłem:

@Override protected void bindShadowClasses() { 
    Robolectric.bindShadowClass(ShadowLog.class); 
    Robolectric.bindShadowClass(ShadowFlashPlayerFinder.class); 
} 

Należy wspomnieć, że mam trochę oszukuje? Oryginalna odpowiedź powyżej jest (oczywiście) poprawna. Więc używam to dla mojej prawdziwej klasy:

package android.niftyco; 

public class FlashPlayerFinder { 
    .. . 

I moje makiety (cień) jest z powrotem w moim pakiecie testowym, jak można by się spodziewać:

package com.niftyco.android.test; 

@Implements(FlashPlayerFinder.class) 
public class ShadowFlashPlayerFinder { 
    @RealObject private FlashPlayerFinder realFPF; 

    public void __constructor(Context c) { 
     //note the construction 
    } 

    @Implementation 
    public boolean isFlashInstalled() { 
     System.out.print("Let's pretend that Flash is installed\n"); 
     return(true); 
    } 
} 
3

Tak, jeśli podklasy RobolectricTestRunner, dodaj niestandardowy pakiet do konstruktora i załaduj swoje klasy Shadow w metodzie bindShadowClasses. Nie trzeba używać sztuczki z pakietem android. *.

(Uwaga: to jest z robolectric-1.1)

Istnieje szereg haków przewidzianych w RobolectricTestRunner # setupApplicationState że można przesłonić.

Oto moja realizacja RobolectricTestRunner.

import org.junit.runners.model.InitializationError; 

import com.android.testFramework.shadows.ShadowLoggerConfig; 
import com.xtremelabs.robolectric.Robolectric; 
import com.xtremelabs.robolectric.RobolectricTestRunner; 

public class RoboRunner extends RobolectricTestRunner { 

public RoboRunner(Class<?> clazz) throws InitializationError { 
    super(clazz); 
    addClassOrPackageToInstrument("package.you're.creating.shadows.of"); 
} 

@Override 
protected void bindShadowClasses() { 
    super.bindShadowClasses(); // as you can see below, you really don't need this 
    Robolectric.bindShadowClass(ShadowClass.class); 
} 

}

Więcej metody można podklasy (od RobolectricTestRunner.class)

/** 
* Override this method to bind your own shadow classes 
*/ 
protected void bindShadowClasses() { 
} 

/** 
* Override this method to reset the state of static members before each test. 
*/ 
protected void resetStaticState() { 
} 

    /** 
* Override this method if you want to provide your own implementation of Application. 
* <p/> 
* This method attempts to instantiate an application instance as specified by the AndroidManifest.xml. 
* 
* @return An instance of the Application class specified by the ApplicationManifest.xml or an instance of 
*   Application if not specified. 
*/ 
protected Application createApplication() { 
    return new ApplicationResolver(robolectricConfig).resolveApplication(); 
} 

Oto, gdzie nazywa się je w Robolectric TestRunner:

public void setupApplicationState(final RobolectricConfig robolectricConfig) { 
    setupLogging(); 
    ResourceLoader resourceLoader = createResourceLoader(robolectricConfig); 

    Robolectric.bindDefaultShadowClasses(); 
    bindShadowClasses(); 

    resourceLoader.setLayoutQualifierSearchPath(); 
    Robolectric.resetStaticState(); 
    resetStaticState(); 

    DatabaseConfig.setDatabaseMap(this.databaseMap);//Set static DatabaseMap in DBConfig 

    Robolectric.application = ShadowApplication.bind(createApplication(), resourceLoader); 
} 
9

ma to znacznie zmieniło się w Robolectric 2. Zamiast tego można podać custom shadows in the configuration pisanie własnego TestRunnera.

Na przykład:

@Config(shadows = {ShadowAudioManager.class, ShadowContextWrapper.class}) 
2

Może być późno, ale stąd: org.robolectric.bytecode.Setup, można znaleźć więcej szczegółów na temat tego, co zajęcia są oprzyrządowanie.

public boolean shouldInstrument(ClassInfo classInfo) { 
    if (classInfo.isInterface() || classInfo.isAnnotation() || classInfo.hasAnnotation(DoNotInstrument.class)) { 
     return false; 
    } 

    // allow explicit control with @Instrument, mostly for tests 
    return classInfo.hasAnnotation(Instrument.class) || isFromAndroidSdk(classInfo); 
    } 

    public boolean isFromAndroidSdk(ClassInfo classInfo) { 
    String className = classInfo.getName(); 
    return className.startsWith("android.") 
     || className.startsWith("libcore.") 
     || className.startsWith("dalvik.") 
     || className.startsWith("com.android.internal.") 
     || className.startsWith("com.google.android.maps.") 
     || className.startsWith("com.google.android.gms.") 
     || className.startsWith("dalvik.system.") 
     || className.startsWith("org.apache.http.impl.client.DefaultRequestDirector"); 
    } 
Powiązane problemy