Android molesta una Dagger2 inyecta dependencia para una prueba de Espresso

Tengo una aplicación fuertemente dependida inyectada ( dagger2 ). Me gustaría ejecutar una prueba de espresso sin tener la prueba de navegar a través de toda la aplicación, e iniciar sesión en la aplicación.

Me gustaría empezar en mi teleActividad, y burlarse del administrador de inicio de sesión. Sin embargo, en cualquier función @test, ya hemos golpeado el puntero nulo como hemos llamado onCreate. Si lo anulamos antes de iniciar la actividad (se muestra a continuación), la actividad es nula.

A mi entender, la capacidad de cambiar nuestras dependencias subrayar es una gran razón por la que utilizamos Dagger2, de lo contrario sería sólo un muy sobre ingeniería singleton. ¿Cómo puedo anular, burlar o cambiar la inyección a un módulo de daga de prueba – para que pueda crear esta sencilla prueba de espresso.

Nota También escribí todo esto en el patrón de diseño MVP si eso hace una diferencia.

Teleactividad

@Inject TelePresenter mTelePresenter; @Inject public LoginStateManager mLoginStateManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ButterKnife.bind(this); DaggerInjectorTele.get().inject(this); mTelePresenter.setTeleDependencies(this); Intent intent = getIntent(); String searchId = null; if (intent != null) { searchId = intent.getStringExtra(Constants.SEARCH_ID); } mTelePresenter.onCreateEvent(searchId, Helper.makeAuthorizationHeader( // CRASH Null pointer mLoginStateManager.getBaseLoginResponse().getAccessToken())); } 

Café exprés

 @LargeTest @RunWith(AndroidJUnit4.class) public class TeleTest { @Rule public ActivityTestRule<TeleActivity> mActivityTestRule = new ActivityTestRule( TeleActivity.class) { @Override protected void beforeActivityLaunched() { super.beforeActivityLaunched(); TeleActivity teleActivity = (TeleActivity)getActivity(); //teleActivity NULL! teleActivity.mLoginStateManager = mock(LoginStateManager.class); LoginResponse loginResponse = mock(LoginResponse.class); when(loginResponse.getAccessToken()).thenReturn("1234"); // Nope here still null when(teleActivity.mLoginStateManager.getBaseLoginResponse()).thenReturn(loginResponse); } }; 

Inyector de Dagger

  public class DaggerInjectorTele { private static TelePresenterComponent telePresenterComponent = DaggerTelePresenterComponent.builder().build(); public static TelePresenterComponent get() { return telePresenterComponent; } } 

TelePresenterComponent

 @Singleton @Component(modules = {TelePresenterModule.class, LoginStateManagerModule.class}) public interface TelePresenterComponent { void inject(TeleActivity activity); } 

TelePresenterModule

 @Module public class TelePresenterModule { @Provides @Singleton public TelePresenter getTelePresenter() { return new TelePresenter(); } } 

LoginStateManagerModule

 @Module public class LoginStateManagerModule { @Provides @Singleton public LoginStateManager getLoginStateManager(){ return new LoginStateManager(); } } 

3 Solutions collect form web for “Android molesta una Dagger2 inyecta dependencia para una prueba de Espresso”

En primer lugar, su decisión de utilizar la inyección de dependencia (Dagger2) es muy buena y de hecho hará que sus pruebas más fáciles de escribir.

Tienes que anular la configuración de inyección de dependencia (módulo) e inyectar un simulacro. Aquí hay un ejemplo sencillo de cómo se puede hacer.

Primero necesitas un simulacro:

 LoginStateManager lsmMock = mock(LoginStateManager.class); 

Ahora anule la configuración DI para usar este simulacro:

 //Extend your TelePresenterModule, override provider method public class TestTelePresenterModule extends TelePresenterModule{ @Override public LoginStateManager getLoginStateManager() { //simply return the mock here return lsmMock; } } 

Ahora a la prueba:

 @Test //this is an espresso test public void withAMock() { //build a new Dagger2 component using the test override TelePresenterComponent componentWithOverride = DaggerTelePresenterComponent.builder() //mind the Test in the class name, see a class above .telePresenterModule(new TestTelePresenterModule()) .build(); //now we initialize the dependency injector with this new config DaggerInjectorTele.set(componentWithOverride); mActivityRule.launchActivity(null); //verify that injected mock was interacted with verify(lsmMock).whatever(); } 

Ejemplo de: https://github.com/yuriykulikov/DIComparison/blob/master/app/src/androidTest/java/com/example/yuriy/dependencyinjectioncomparison/Dagger2Test.java

Parece problema de arquitectura en lugar de un problema menor.

En primer lugar no crearía una clase estática para llamar dagger2 componente mi enfoque sería más android centric, me refiero a la aplicación singleton con todas sus campanas y silbatos.

De todos modos … La mejor manera de ejecutar pruebas sin ejecutar todo el flujo de trabajo es separar su proyecto en dos proyectos diferentes:

1- Aplicación de interfaz de usuario, tus actividades y fragmentos de Android, etc.

2-Logic Module utilizando una arquitectura de la empresa decir MVP / MVC / MVVM (debe ser un proyecto diferente dentro de su estudio de Android)

¿Dónde debe usar daga? Dentro de su aplicación de interfaz de usuario para pegar el módulo de lógica en su interfaz de usuario.

¿Cómo puedes probar diferentes partes de la aplicación (Logic Module)? Ya que separó su lógica en diferentes escrituras de escritura de parte para ellos sería mucho más fácil, aunque usted no va a necesitar Esperesso más. Simple unidad de pruebas con JUnit y Mockito puede ayudarle sin ejecutar todo el flujo de trabajo.

Tenga en cuenta que no debe tener ningún tipo de lógica dentro de su aplicación de interfaz de usuario.

Mi opinión es Clean Architecture: https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

Tengo un andamio simple para el acercamiento anterior en mi github usted puede leer eso también, bien si usted tiene gusto: https://github.com/vahidhashemi/android_clean_architecture

No hay valor establecido en

LoginStateManager

Por lo que al construir el componente obtendrá la dependencia de TelePresenter y la dependencia de LoginStateManager, pero no los valores establecidos en las variables miembro de ambos. Así que creo que necesita establecer los valores de las variables miembro antes de acceder a ellos.

 getBaseLoginResponse().getAccessToken()) 

La línea de código anterior le da nulo porque no ha establecido el valor. Así que antes de acceder a él, debe establecer los valores primero

  • SecurityProvider en Mockito Pruebas cuando se ejecuta junto a Robolectric
  • Prueba Unitaria de Retrofit 2 api call con Mockito
  • Mockito / Power Mockito: incapaz de obtener la salida esperada cuando el método de burla de LayoutParams en android
  • ¿Cómo puedo burlarme del contexto usando Mockito y Robolectric?
  • Necesita ayuda para escribir una prueba de unidad usando Mockito y JUnit4
  • Junit4 abrir un getResources (). OpenRawResource usando mockito ejecuta nullpointer
  • Cómo burlar una SharedPreferences usando Mockito
  • Java.lang.AbstractMethodError cuando espía la LinkedList en Android
  • Apkbuilder encuentra el archivo duplicado al agregar powermock a un proyecto de prueba de android
  • Llamadas de método de burla usando power mockito - org.powermock.api.mockito.ClassNotPreparedException
  • Cómo probar métodos de unidad que interactúan con clases de sistema (o Android)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.