2015-09-03 23 views
31

Sto cercando di integrare i casi di test unitario per ogni blocco di codice possibile. Ma sto affrontando problemi durante l'aggiunta di casi di test per le chiamate API che sono effettuate tramite aggiornamento.Come test delle unità Retrofit api chiama

Il compilatore JUnit non esegue mai il codice nelle funzioni CallBack.

C'è un'altra opzione di effettuare tutte le chiamate api Synchronous a scopo di test, ma questo non è possibile per ogni caso nella mia app.

Qualcuno può aiutarmi a risolvere questo problema. Devo aggiungere casi di test nelle chiamate API con qualsiasi mezzo.

Qualsiasi suggerimento per un altro approccio sarà anche utile.

Grazie in anticipo!

risposta

18

Eseguo il test delle richiamate di Retrofit utilizzando le librerie Mockito, Robolectric e Hamcrest.

Prima di tutto, istituito pila lib nel build.gradle del modulo:

dependencies { 
    testCompile 'org.robolectric:robolectric:3.0' 
    testCompile "org.mockito:mockito-core:1.10.19" 
    androidTestCompile 'org.hamcrest:hamcrest-library:1.1' 
} 

In build.gradle globale del progetto jour aggiungere la seguente riga al buildscript dipendenze:

classpath 'org.robolectric:robolectric-gradle-plugin:1.0.1' 

Quindi, immettere " Build Variants "in Android Studio (per trovarlo rapidamente, premi Ctrl + Shift + A e cercalo), e cambia l'opzione" Test Artifact "in" Unit Test ". Android Studio cambierà la cartella di test in "com.your.package (test)" (anziché AndroidTest).

Ok. Il set-up è terminato, è tempo di scrivere alcuni test!

Supponiamo che tu abbia alcune chiamate di retrofit api per recuperare un elenco di oggetti che devono essere inseriti in qualche adattatore per un RecyclerView ecc. Vorremmo testare se l'adattatore viene riempito con gli elementi appropriati in caso di chiamata riuscita. Per fare ciò, sarà necessario cambiare l'implementazione dell'interfaccia Retrofit, che si utilizza per effettuare chiamate con un mock, e fare alcune risposte false sfruttando la classe ArgockCaptor di Mockito.

@Config(constants = BuildConfig.class, sdk = 21, 
    manifest = "app/src/main/AndroidManifest.xml") 
@RunWith(RobolectricGradleTestRunner.class) 
public class RetrofitCallTest { 

    private MainActivity mainActivity; 

    @Mock 
    private RetrofitApi mockRetrofitApiImpl; 

    @Captor 
    private ArgumentCaptor<Callback<List<YourObject>>> callbackArgumentCaptor; 

    @Before 
    public void setUp() {    
     MockitoAnnotations.initMocks(this); 

     ActivityController<MainActivity> controller = Robolectric.buildActivity(MainActivity.class); 
     mainActivity = controller.get(); 

     // Then we need to swap the retrofit api impl. with a mock one 
     // I usually store my Retrofit api impl as a static singleton in class RestClient, hence: 
     RestClient.setApi(mockRetrofitApiImpl); 

     controller.create(); 
    } 

    @Test 
    public void shouldFillAdapter() throws Exception { 
     Mockito.verify(mockRetrofitApiImpl) 
      .getYourObject(callbackAgrumentCaptor.capture()); 

     int objectsQuantity = 10; 
     List<YourObject> list = new ArrayList<YourObject>(); 
     for(int i = 0; i < objectsQuantity; ++i) { 
      list.add(new YourObject()); 
     } 

     callbackArgumentCaptor.getValue().success(list, null); 

     YourAdapter yourAdapter = mainActivity.getAdapter(); // Obtain adapter 
     // Simple test check if adapter has as many items as put into response 
     assertThat(yourAdapter.getItemCount(), equalTo(objectsQuantity)); 
    } 
} 

Procedere con il test facendo clic con il pulsante destro del mouse sulla classe di test e premendo Esegui.

E questo è tutto. Suggerisco caldamente di usare Robolectric (con il plugin gradle robolectric) e Mockito, queste librerie rendono più semplice testare le app Android. Ho imparato questo metodo dal seguente blog post. Inoltre, fare riferimento a this answer.

Aggiornamento: Se si utilizza Retrofit con RxJava, controllare anche my other answer on that.

+1

ho letto lo stesso post sul blog ed ha trovato le spiegazioni di essere utile. Un solo punto per me è stato l'esempio. Ho provato a leggere l'esempio e quindi a implementare i test in modo simile sul mio progetto. Quello che ho imparato, che non era chiaro dallo snippet del codice di test, era che nel test descritto nel post del blog c'è un'attività che fa la chiamata di rete nel metodo onCreate(). Questa chiamata deve avvenire in modo che nel test possa essere eseguita la chiamata a Mockito.verify(). Se non si effettua la chiamata "di rete" nel codice dell'applicazione, il codice di test non verrà eseguito così com'è. – neonDion

+0

Questa non è la risposta alla domanda –

+0

@JemshitIskenderov come mai? cura di sottolineare il problema con esso? – maciekjanusz

6

Se si utilizza .execute() al posto di.enqueue() rende l'esecuzione sincrono, in tal modo i test possono corse correttamente senza la necessità di importare librerie 3 differenti e l'aggiunta di alcun codice o modificare le varianti di compilazione.

come:

public class LoginAPITest { 

    @Test 
    public void login_Success() { 

     APIEndpoints apiEndpoints = RetrofitHelper.getTesterInstance().create(APIEndpoints.class); 

     Call<AuthResponse> call = apiEndpoints.postLogin(); 

     try { 
      //Magic is here at .execute() instead of .enqueue() 
      Response<AuthResponse> response = call.execute(); 
      AuthResponse authResponse = response.body(); 

      assertTrue(response.isSuccessful() && authResponse.getBearer().startsWith("TestBearer")); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

    } 

} 
+0

Mentre questo è un approccio valido, la domanda afferma _C'è un'altra opzione di fare tutte le chiamate API sincrone a scopo di test, ma questo non è possibile per ogni caso nella mia app._ – maciekjanusz

+0

mybad mybad mybad –

+2

ottima soluzione, grazie! – Benobab

Problemi correlati