Confundido cómo usar Mockito para una prueba de Android

Estoy tratando de escribir una prueba de unidad para mi aplicación Android, pero tener problemas para hacer lo que quiero con mockito. Esto se está utilizando en conjunción con Robolectric que he trabajado muy bien y han demostrado que las pruebas de unidad de trabajo.

Quiero probar si un botón abrirá una nueva actividad dependiendo de si hay algún dispositivo bluetooth conectado. Obviamente, no hay ningún dispositivo conectado con bluetooth en mi prueba, sin embargo quiero fingir como si no hay. El estado de la conexión Bluetooth se almacena en mi clase de aplicación. No hay un método públicamente accesible para cambiar este valor.

Así que básicamente la lógica en la aplicación es así:

HomeActivity.java:

//this gets called when the button to open the list is clicked. public void openListActivity(View button) { MyApplication myApplication = (MyApplication) getApplication(); if (myApplication.isDeviceConnected() { startActivity(new intent(this, ListActivity.class)); } } 

Así que para probar esto hice lo siguiente:

TestHomeActivity.java:

 @Test public void buttonShouldOpenListIfConnected() { FlexApplication mockedApp = Mockito.mock(MyApplication.class); Mockito.when(mockedApp.isDeviceConnected()).thenReturn(true); //listViewButton was setup in @Before listViewButton.performClick(); ShadowActivity shadowActivity = Robolectric.shadowOf(activity); Intent intent = shadowActivity.getNextStartedActivity(); assertNotNull(intent); //this fails because no new activity was opened. I debugged this and found that isDeviceConnected returned false. ShadowIntent shadowIntent = Robolectric.shadowOf(intent); assertThat(shadowIntent.getComponent().getClassName(), equalTo(ListActivity.class.getName())); } 

Así que mi unidad de prueba falla porque la llamada (en la actividad) a isDeviceConnected devuelve false, aunque pensé que le dije que devolver true con el marco de simulación. Quiero que mi prueba para que este método devuelva true sin embargo. ¿No es esto lo que mockito hace o estoy totalmente equivocado sobre cómo usar mockito?

Así es como funciona mockito, pero el problema es: ¿es tu listViewButton usando tu mockedApp ? Parece que no, porque está creando mockedApp en el método de prueba y nunca lo pone en cualquier lugar. Mockito no se burlará de las llamadas de método de todas las instancias de la Application , sólo de lo que declaró como un simulacro.

Personalmente, no sé cómo androide funciona con la clase de Application , pero tendrá que establecerlo en algún lugar para que listView utilizar su mockedApp lugar de lo que recibe normalmente.

EDIT Después de la pregunta actualizada, puede transformar su getApplication en un método protegido, spy listViewButton y hacer que devuelva su mockedApp . Eso huele un poco mal, pero es una manera si no puede establecer su aplicación objeto de burla a listViewButton .

EDIT2

Ejemplo de usar espía en su prueba usando BDDMockito para la lectura 🙂

 public HomeActivity { ... protected MyApplication getApplication() { // real code } ... } public void TestHomeActivity { private HomeActivity homeActivity; @Before public void setUp() { this.homeActivity = spy(new HomeActivity()); } @Test public void buttonShouldOpenListIfConnected() { // given FlexApplication mockedApp = Mockito.mock(MyApplication.class); Mockito.when(mockedApp.isDeviceConnected()).thenReturn(true); // IMPORTANT PART given(homeActivity.getApplication()).willReturn(mockedApp); ... } } 

Después de eso, su prueba debería funcionar como se esperaba. Pero refuerzo: Use spy sólo si no puede inyectar su mockedApp dentro de mockedApp .

No se está invocando tu versión de imitación.

¿Ve esa llamada, getApplication() ? (abajo). Eso está devolviendo una copia real de su clase de MyApplication, no su versión de imitación. Tendrías que interceptar la llamada getApplication() y pasar en tu objeto de aplicación getApplication() .

 HomeActivity.java: //this gets called when the button to open the list is clicked. public void openListActivity(View button) { MyApplication myApplication = (MyApplication) getApplication(); // returns the real thing if (myApplication.isDeviceConnected() { startActivity(new intent(this, ListActivity.class)); } } 

No estoy seguro de que esto sea posible con Mockito. ¿Ha intentado personalizar el método ShadowActivity # getApplication ()?

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.