Prueba de unidad de Android con Retrofit y Mockito
He separado los métodos de api retrofit de los métodos del código de actividad y quiero hacer una prueba de unidad en estos métodos, un ejemplo: La interfaz:
public interface LoginService { @GET("/auth") public void basicLogin(Callback<AuthObject> response); }
Y este es el método que hacen la llamada, en la actividad principal me sale el objeto por el bus de eventos.
- ¿Cómo llamo a una intención en Retrofit Callback?
- Observer.onError disparando de manera incoherente
- ¿Tenemos alguna posibilidad de detener la solicitud en OkHttp Interceptor?
- RxJava alternativa para el operador map () para guardar los elementos emitidos
- Error: tipos incompatibles: GsonConverterFactory no se puede convertir en Factory
public class AuthAPI { private Bus bus; LoginService loginService; public AuthAPI(String username, String password) { this.bus = BusProvider.getInstance().getBus(); loginService = ServiceGenerator.createService(LoginService.class, CommonUtils.BASE_URL, username, password); } public void Login() { loginService.basicLogin(new Callback<AuthObject>() { @Override public void success(AuthObject authObject, Response response) { bus.post(authObject); } @Override public void failure(RetrofitError error) { AuthObject authObject = new AuthObject(); authObject.setError(true); bus.post(authObject); } }); } }
Y aquí la prueba
@RunWith(MockitoJUnitRunner.class) public class AuthCallTest extends TestCase { AuthAPI authAPI; @Mock private LoginService mockApi; @Captor private ArgumentCaptor<Callback<AuthObject>> cb; @Before public void setUp() throws Exception { authAPI = new AuthAPI("username", "password"); MockitoAnnotations.initMocks(this); } @Test public void testLogin() throws Exception { Mockito.verify(mockApi).basicLogin((cb.capture())); AuthObject authObject = new AuthObject(); cb.getValue().success(authObject, null); assertEquals(authObject.isError(), false); } }
Cuando inicio la prueba tengo este error
Wanted but not invoked: mockApi.basicLogin(<Capturing argument>); -> at AuthCallTest.testLogin(AuthCallTest.java:42) Actually, there were zero interactions with this mock.
Lo que hice mal, esto me está volviendo loco Traté de seguir esta guía sin éxito: http://www.mdswanson.com/blog/2013/12/16/reliable-android-http-testing-with-retrofit-and –mockito.html
Alguien ayúdeme 🙁
- Encadenamiento de servicios de Retrofit con soporte de RxJava
- Manejo de errores personalizados con Retrofit cuando se ofusca usando proguard da java.lang.reflect.UndeclaredThrowableException
- Retrofit: ¿Cómo especificar parámetros separados por comas en la solicitud?
- Uso de MultipartTypedOutput
- Cómo manejar el `IllegalArgumentException` en RxJava?
- Configuración de Android studio 1.1.0 minifyEnabled true causando problemas con la aplicación
- Cómo manejar la paginación en retrofit
- Uso de Retrofit para acceder a una API con key / id
El artículo no es muy claro ya que echa de menos los pasos de configuración. Al visitar el proyecto GitHub enlazado en el artículo, puede ver el código fuente completo que explica los pasos que faltan:
1) Las muestras de código se extraen de una clase de prueba que prueba una actividad específica. Como parte de la configuración (es decir, en @Before
), reemplaza la referencia de la actividad a una implementación de la API de GitHub con una simulación. A continuación, llama a la actividad onCreate()
.
2) Durante onCreate()
, la actividad realiza una llamada a la API GitHub ahora reemplazada, pasando su objeto de Callback
.
Estos dos primeros pasos explican por qué los Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture());
Paso al comienzo de cada prueba funciona. Como la prueba se ejecuta después de @Before
, el mockApi ha hecho una llamada en su método repositories()
.
El resto del código es más fácil de entender una vez que está en su lugar. Como sólo ha creado un mockApi
, pero no ha cambiado la Callback
real que se utiliza, se cambia el contenido de la actividad. El resto del código verifica que esos cambios han tenido lugar, ya sea comprobando un ListView o el Toasts.
Así que para responder a su pregunta, usted necesita:
1) Al inicio del método de prueba, reemplace el objeto loginService de AuthAPI con su objeto mockApi y, a continuación, llame a AuthAPI.Login()
.
2) Utilice verify()
como ya está para comprobar que la función ha sido llamada.
3) Crear un AuthObject
ejemplo y pasarlo a la función cb.getValue().success()
.
4) Obtenga el AuthObject
de su Bus
y afirme que es el mismo que envió a la función callback.success()
.
Esto prueba que AuthAPI.Login()
envía correctamente a su Bus
el AuthObject
que recuperaría de Retrofit.
(Me doy cuenta de que la pregunta de SO fue escrita hace algún tiempo, pero como encontré el mismo artículo y tuve la misma confusión muy recientemente, pensé que esta respuesta podría ser útil para otros.)
El problema es que usted llama a verify
en el momento equivocado: el propósito de verify
es verificar que las interacciones con mockApi fueron lo que esperaba. Tan normalmente usted vería algo como:
authApi.login(); Mockito.verify(mockApi).basicLogin((cb.capture()));
Eso es también lo que el mensaje de error le está diciendo: verify
basicLogin
esperado para ser llamado, pero no lo fue.
He leído ese artículo también y sentí que faltaba algo. Todavía no entiendo la captura de argumentos. Así que no puedo ayudarte con eso 🙂
- Google Play no me permite actualizar mi aplicación
- Mostrar el teclado virtual de SearchView en ActionBar