J'essaie d'intégrer des scénarios de test unitaires pour chaque bloc de code possible . Mais je suis confronté à des problèmes lors de l'ajout de scénarios de test pour les appels d'API qui sont effectués via la conversion ultérieure.
Le compilateur JUnit n'exécute jamais le code dans les fonctions CallBack} _.
Il existe une autre possibilité de passer tous les appels d'API Synchrone à des fins de test, mais ce n'est pas possible dans tous les cas dans mon application.
Comment puis-je résoudre ce problème? Je dois ajouter des cas de test dans les appels API par quelque moyen que ce soit.
Je teste mes rappels Retrofit en utilisant les bibliothèques Mockito, Robolectric et Hamcrest.
Tout d'abord, configurez la pile de lib dans le build.gradle de votre module:
dependencies {
testCompile 'org.robolectric:robolectric:3.0'
testCompile "org.mockito:mockito-core:1.10.19"
androidTestCompile 'org.hamcrest:hamcrest-library:1.1'
}
Dans le build.gradle global du projet actuel, ajoutez la ligne suivante aux dépendances buildscript:
classpath 'org.robolectric:robolectric-gradle-plugin:1.0.1'
Puis entrez dans le menu "Variantes de construction" dans Android Studio (pour le trouver rapidement, appuyez sur Ctrl + Maj + A et recherchez-le), puis basculez l'option "Tester l'artefact" sur "Tests unitaires". Android studio basculera votre dossier de test sur "com.votre.package (test)" (au lieu de androidTest).
D'accord. La configuration est terminée, il est temps d'écrire des tests!
Supposons que vous ayez des appels d'api de modification pour récupérer une liste d'objets devant être insérés dans un adaptateur pour RecyclerView, etc. Nous voudrions vérifier si l'adaptateur se remplit avec les éléments appropriés lors d'un appel réussi . Pour cela, nous devrons changer d'implémentation d'interface Retrofit, que vous utiliserez pour passer des appels fantômes, et créer de fausses réponses en exploitant la classe Mockito ArgumentCaptor.
@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(callbackArgumentCaptor.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));
}
}
Procédez au test en cliquant avec le bouton droit de la souris sur la classe de test et en appuyant sur Exécuter.
Et c'est tout. Je suggère fortement d'utiliser Robolectric (avec le plugin robolectric gradle) et Mockito, ces bibliothèques facilitent grandement le test des applications Android . J'ai appris cette méthode à partir du blog post . Voir aussi cette réponse .
Update: Si vous utilisez Retrofit avec RxJava, consultez mon autre réponse à ce sujet aussi.
Si vous utilisez .execute () au lieu de .enqueue (), l'exécution est synchronisée. Les tests peuvent donc s'exécuter correctement sans qu'il soit nécessaire d'importer 3 bibliothèques différentes et d'ajouter du code ou de modifier les variantes de construction.
Comme:
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();
}
}
}
Le framework JUnit n'exécute jamais le code dans les fonctions CallBack car le thread d'exécution principal se termine avant l'extraction de la réponse. Vous pouvez utiliser CountDownLatch
comme indiqué ci-dessous:
@Test
public void testApiResponse() {
CountDownLatch latch = new CountDownLatch(1);
mApiHelper.loadDataFromBackend(new Callback() {
@Override
public void onResponse(Call call, Response response) {
System.out.println("Success");
latch.countDown();
}
@Override
public void onFailure(Call call, Throwable t) {
System.out.println("Failure");
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Cet échantillon de test } peut également être utile.
si déjà encapsulation retrofit2.0 avec rx avec reposant
open class BaseEntity<E> : Serializable {
/*result code*/
var status: Int = 0
/**data */
var content: E? = null
}
et demande d'api de serveur comme
@GET(api/url)
fun getData():Observable<BaseEntity<Bean>>
votre service rappelle une seule demande de synchronisation Observable
val it = service.getData().blockingSingle()
assertTrue(it.status == SUCCESS_CODE)