2015-05-01 16 views
11

ho separati retrofit API chiama i metodi del codice attività e voglio fare una prova di unità su questi metodi, un esempio: L'interfaccia:Android Unità di prova con Retrofit e Mockito

public interface LoginService { 
    @GET("/auth") 
    public void basicLogin(Callback<AuthObject> response); 
} 

e questo è il metodo che effettua la chiamata, nell'attività principale ottengo l'oggetto dal bus eventi.

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); 
      } 
     }); 
    } 

} 

Ed ecco il test

@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); 
    } 
} 

quando lancio il test che ho questo errore

Wanted but not invoked: 
mockApi.basicLogin(<Capturing argument>); 
-> at AuthCallTest.testLogin(AuthCallTest.java:42) 
Actually, there were zero interactions with this mock. 

Quello che ho fatto di sbagliato, questo mi sta facendo impazzire Ho provato a seguire questa guida senza successo: http://www.mdswanson.com/blog/2013/12/16/reliable-android-http-testing-with-retrofit-and-mockito.html

someon e help me :(

+0

Il problema è che stai seguendo un blog che ha più di due anni. Inoltre, quell'autore non aggiorna il suo codice per due anni e non ha interesse a. –

risposta

21

L'articolo non è molto chiaro in quanto manca la procedura di installazione. Visitando lo GitHub project collegato all'articolo, è possibile visualizzare il codice sorgente completo che spiega i passaggi mancanti:

1) Gli esempi di codice vengono estratti da una classe di test che verifica un'attività specifica. Come parte dell'impostazione (ad esempio in @Before), sostituisce il riferimento dell'attività a un'implementazione dell'API GitHub con una simulazione. Quindi chiama l'attività onCreate().

2) Durante lo onCreate(), l'attività effettua una chiamata all'API GitHub ora sostituita, passando nell'oggetto Callback.

Questi primi due passaggi spiegano perché il passaggio Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture()); all'inizio di ogni test funziona. Poiché il test viene eseguito dopo @Before, il mockApi ha effettivamente ricevuto una chiamata sul suo metodo .

Il resto del codice è più facile da capire una volta che è a posto. Poiché ha creato solo un mockApi, ma non ha modificato l'attuale Callback in uso, il contenuto dell'attività viene modificato. Il resto del codice verifica quindi che tali modifiche abbiano avuto luogo, controllando un ListView o i Toasts.


Quindi, per rispondere alla tua domanda, è necessario:

1) All'inizio del tuo metodo di prova, sostituire oggetto loginService del AuthAPI con il vostro oggetto mockApi, quindi chiamare AuthAPI.Login().

2) Utilizzare verify() come già si verifica per richiamare la funzione.

3) Creare un campione AuthObject e passarlo alla funzione cb.getValue().success().

4) Ottenere AuthObject dal Bus e affermare che è lo stesso che è stato inviato alla funzione callback.success().

Questo test che il tuo AuthAPI.Login() invia correttamente al tuo Bus il AuthObject che avrebbe recuperato da Retrofit.


(mi rendo conto che la questione SO è stato scritto qualche tempo fa, ma come mi sono imbattuto lo stesso articolo e aveva la stessa confusione a poco tempo fa, ho pensato che questa risposta potrebbe essere utile per gli altri.)

+0

Grazie per la segnalazione. – rogerstone

+0

Sembra che tu voglia strumentare i tuoi test con il contesto di attività Android. Non penso che questo sia l'approccio più puro per testare le API REST, che dovrebbero essere testate su JVM (junit). –

+1

@IgorGanapolsky Non è possibile testare direttamente le API REST in un'app Android in JUnit se si utilizza qualsiasi classe che fa riferimento all'SDK Android, poiché JUnit non carica le classi Android. Tuttavia, questo è lo scopo dell'articolo precedente: come utilizzare Robolectric e Mockito per eseguire test locali delle API REST senza effettuare effettive chiamate al server, pur continuando ad accedere alle vere classi Android. –

1

Il problema è che chiami verify nel momento sbagliato: lo scopo di verify è verificare che le interazioni con mockApi fossero quelle che ti aspettavi. Quindi normalmente si vede qualcosa di simile:

authApi.login(); 
Mockito.verify(mockApi).basicLogin((cb.capture())); 

Questo è anche ciò che il messaggio di errore che dice: verify previsto basicLogin di essere chiamato, ma non lo era.

Ho letto anche quell'articolo e ho sentito che mancava qualcosa. In realtà non approfondisco ancora la discussione sull'argomento. Quindi non posso aiutarti con questo :)

Problemi correlati