2011-08-30 10 views

Respuesta

11

La respuesta corta es no.

Robolectric es selectivo sobre qué clases que intercepta y los instrumentos. En el momento de escribir estas líneas, las únicas clases que serán instrumentadas deben tener una correspondencia nombre de clase completamente calificado uno de estos selectores:

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

Toda la razón de ser de Robolectric es que las clases establecidas en el tiro tarro de Android SDK excepciones cuando se invoca en una JVM (es decir, no en un emulador o dispositivo). La actividad de su aplicación tiene una fuente que no es 'hostil' (probablemente no arroje excepciones cuando se invocan los métodos o constructores). El propósito de Robolectric es permitirle poner bajo prueba el código de su aplicación, que de otro modo no sería posible debido a la forma en que se escribe el SDK. Algunas de las otras razones por las cuales se creó Robolectric fueron:

  • El SDK no siempre tiene métodos que permiten consultar el estado de los objetos manipulados por Android código de la aplicación. Las sombras se pueden escribir para proporcionar acceso a este estado.
  • Muchas de las clases y métodos en el SDK de Android son finales y/o privada o protegida, por lo que es difícil crear las dependencias que necesita su código de aplicación que de otro modo estar disponibles para el código de aplicación.

El código se puede cambiar claramente para sombrear cualquier clase. Se ha hablado en el pasado sobre la extracción de las características de sombreado en una biblioteca independiente, para ayudar a las pruebas de escritura con alguna otra API de prueba hostil.

¿Por qué quiere a la sombra de su actividad?

+0

Gracias por la explicación. La razón por la que quiero sombrear mi Actividad es porque la inicia mi aplicación con una llamada a 'startActivityForResult (..)'. Tengo este código: 'ShadowActivity shadowActivity = shadowOf (activityA); \t \t startedIntent Intención = shadowActivity.getNextStartedActivity(); \t \t ShadowIntent shadowIntent = shadowOf (startedIntent); \t \t assertThat (. ShadowIntent.getComponent() GetClassName(), equalTo (activityB.class.getName())); 'Quiero obtener las vistas desde activityB. Usando la API nativa, utilicé un 'ActivityMonitor' pero quiero saber cómo hacerlo usando Robolectric. – kaneda

2

Como una actualización, que han sido capaces de crear sombras de mis propias clases, siempre y cuando soy cuidadoso para obligar a la clase de sombra antes de cualquier posible cargador actúa en dicha clase. Así, de acuerdo con las instrucciones, en el RoboRunner que hice:

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

¿le he dicho que yo estoy engañando un poco? La respuesta original anterior es (por supuesto) correcta. Así que lo uso para mi clase real:

package android.niftyco; 

public class FlashPlayerFinder { 
    .. . 

Y mi maqueta (sombra) es en la parte trasera de mi paquete de prueba, como era de esperar:

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

Sí, si subclase el RobolectricTestRunner, agregue un paquete personalizado al constructor y cargue sus clases de sombra en el método bindShadowClasses. No es necesario usar el truco del paquete android. *.

(Nota: esto es con robolectric-1,1)

Hay una serie de ganchos previstos en el RobolectricTestRunner # setupApplicationState que se puede reemplazar.

Aquí está mi aplicación de la 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); 
} 

}

Más métodos que puede subclase (de 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(); 
} 

Aquí es donde se les llama en el 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

Esto tiene cambiado significativamente con Robolectric 2. Puede especificar custom shadows in the configuration en lugar de escribiendo su propio TestRunner.

Por ejemplo:

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

podría ser tarde, pero a partir de aquí: org.robolectric.bytecode.Setup, es posible encontrar más detalles acerca de qué clases están instrumentadas.

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"); 
    } 
Cuestiones relacionadas