web-dev-qa-db-fra.com

Android Test unitaire avec Retrofit2 et Mockito ou Robolectric

Puis-je tester la réponse réelle de retrofit2beta4? Ai-je besoin de Mockito ou de Robolectic?

Je n'ai pas d'activités dans mon projet, ce sera une bibliothèque et je dois tester si le serveur répond correctement. Maintenant, j'ai un tel code et coincé ...

@Mock
ApiManager apiManager;

@Captor
private ArgumentCaptor<ApiCallback<Void>> cb;

@Before
public void setUp() throws Exception {
    apiManager = ApiManager.getInstance();
    MockitoAnnotations.initMocks(this);
}

@Test
public void test_login() {
    Mockito.verify(apiManager)
           .loginUser(Mockito.eq(login), Mockito.eq(pass), cb.capture());
    // cb.getValue();
    // assertEquals(cb.getValue().isError(), false);
}

Je peux donner une fausse réponse, mais il faut que je teste réellement. Est-ce le succès? Est-ce que le corps est correct? Pouvez-vous m'aider avec le code?

48
AndrewS

La réponse est trop simple que ce à quoi je m'attendais:

Utiliser CountDownLatch fait attendre votre test jusqu'à ce que vous appeliez countDown ()

public class SimpleRetrofitTest {

private static final String login = "your@login";
private static final String pass = "pass";
private final CountDownLatch latch = new CountDownLatch(1);
private ApiManager apiManager;
private OAuthToken oAuthToken;

@Before
public void beforeTest() {
    apiManager = ApiManager.getInstance();
}

@Test
public void test_login() throws InterruptedException {
    Assert.assertNotNull(apiManager);
    apiManager.loginUser(login, pass, new ApiCallback<OAuthToken>() {
        @Override
        public void onSuccess(OAuthToken token) {
            oAuthToken = token;
            latch.countDown();
        }

        @Override
        public void onFailure(@ResultCode.Code int errorCode, String errorMessage) {
            latch.countDown();
        }
    });
    latch.await();
    Assert.assertNotNull(oAuthToken);
}

@After
public void afterTest() {
    oAuthToken = null;
}}
17
AndrewS

Ce n’est généralement pas une bonne idée de tester les requêtes de serveurs réels. Voir cet article de blog pour une discussion intéressante sur le sujet. Selon l'auteur, l'utilisation de votre vrai serveur est un problème pour les raisons suivantes:

  • Une autre pièce en mouvement qui peut échouer par intermittence
  • Requiert des compétences en dehors du domaine Android pour déployer le serveur et le maintenir à jour)
  • Difficile de déclencher une erreur/cas Edge
  • Exécution lente du test (appels HTTP en cours)

Vous pouvez éviter tous les problèmes ci-dessus en utilisant un serveur fictif tel que OkHttp's MockWebServer pour simuler des résultats de réponse réels. Par exemple:

@Test
public void test() throws IOException {
    MockWebServer mockWebServer = new MockWebServer();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(mockWebServer.url("").toString())
            //TODO Add your Retrofit parameters here
            .build();

    //Set a response for retrofit to handle. You can copy a sample
    //response from your server to simulate a correct result or an error.
    //MockResponse can also be customized with different parameters
    //to match your test needs
    mockWebServer.enqueue(new MockResponse().setBody("your json body"));

    YourRetrofitService service = retrofit.create(YourRetrofitService.class);

    //With your service created you can now call its method that should 
    //consume the MockResponse above. You can then use the desired
    //assertion to check if the result is as expected. For example:
    Call<YourObject> call = service.getYourObject();
    assertTrue(call.execute() != null);

    //Finish web server
    mockWebServer.shutdown();
}

Si vous devez simuler des retards de réseau, vous pouvez personnaliser votre réponse comme suit:

MockResponse response = new MockResponse()
    .addHeader("Content-Type", "application/json; charset=utf-8")
    .addHeader("Cache-Control", "no-cache")
    .setBody("{}");
response.throttleBody(1024, 1, TimeUnit.SECONDS);

Vous pouvez également utiliser MockRetrofit et NetworkBehavior pour simuler les réponses de l'API. Voir ici un exemple d'utilisation.

Enfin, si vous souhaitez simplement tester votre service de modernisation, le plus simple consiste à en créer une version factice qui émet des résultats fictifs pour vos tests. Par exemple, si vous avez l'interface de service GitHub suivante:

public interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(
        @Path("owner") String owner,
        @Path("repo") String repo);
}

Vous pouvez ensuite créer le MockGitHub suivant pour vos tests:

public class MockGitHub implements GitHub {
    private final BehaviorDelegate<GitHub> delegate;
    private final Map<String, Map<String, List<Contributor>>> ownerRepoContributors;

    public MockGitHub(BehaviorDelegate<GitHub> delegate) {
        this.delegate = delegate;
        ownerRepoContributors = new LinkedHashMap<>();

        // Seed some mock data.
        addContributor("square", "retrofit", "John Doe", 12);
        addContributor("square", "retrofit", "Bob Smith", 2);
        addContributor("square", "retrofit", "Big Bird", 40);
        addContributor("square", "picasso", "Proposition Joe", 39);
        addContributor("square", "picasso", "Keiser Soze", 152);
    }

    @Override public Call<List<Contributor>> contributors(String owner, String repo) {
        List<Contributor> response = Collections.emptyList();
        Map<String, List<Contributor>> repoContributors = ownerRepoContributors.get(owner);
        if (repoContributors != null) {
            List<Contributor> contributors = repoContributors.get(repo);
            if (contributors != null) {
                response = contributors;
            }
        }
        return delegate.returningResponse(response).contributors(owner, repo);
    }
}

Vous pouvez ensuite utiliser le MockGitHub sur vos tests pour simuler le type de réponses que vous recherchez. Pour l'exemple complet, voir les implémentations des SimpleService et SimpleMockService pour cela Exemple de modification .

Cela dit, si vous devez absolument vous connecter au serveur actuel, vous pouvez configurer Retrofit pour qu’il fonctionne de manière synchrone avec un ImmediateExecutor personnalisé:

public class ImmediateExecutor implements Executor {
    @Override public void execute(Runnable command) {
        command.run();
    }
}

Puis appliquez-le au OkHttpClient que vous utilisez lors de la construction de la modification:

OkHttpClient client = OkHttpClient.Builder()
        .dispatcher(new Dispatcher(new ImmediateExecutor()))
        .build();

Retrofit retrofit = new Retrofit.Builder()
        .client(client)
        //Your params
        .build();
105
Ricardo

Sauf si vous testez l'API du serveur QA, il s'agit d'une mauvaise idée pour plusieurs raisons.

  • Premièrement, vous remplissez votre base de données de production avec des données incorrectes.
  • Utilisation des ressources du serveur, quand ils peuvent mieux utiliser pour servir une demande valide

La meilleure façon d'utiliser Mockito ou de simuler vos réponses

De même, si vous devez tester votre API de production, testez-la une fois et ajoutez l'annotation @Ignore. De cette façon, ils ne sont pas exécutés tout le temps et ne polluez pas votre serveur avec de fausses données. Vous pouvez les utiliser dès que vous estimez que l'API ne se comporte pas correctement.

0
Akshay