Test de l'Unité Android 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 je suis 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 faire une fausse réponse, mais je dois tester réel. Est-il le succès? Est-il du corps correcte? Pouvez-vous m'aider avec le code?

43
demandé sur AndrewS 2016-03-02 16:32:02

3 réponses

ce n'est généralement pas une bonne idée de tester de vraies requêtes de serveur. Voir ce post pour une discussion intéressante sur le sujet. Selon l'auteur, utiliser votre serveur réel est un problème car:

  • une Autre pièce qui peut échouer par intermittence
  • nécessite une certaine expertise en dehors du domaine Android pour déployer le serveur et le maintenir à jour
  • Difficile pour déclencher d'erreur/cas isolés
  • exécution de test lente (toujours en train de faire des appels HTTP)

vous pouvez éviter tous les problèmes ci-dessus en utilisant un serveur simulé tel que 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 avez besoin de simuler des retards 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);

Alternativement, vous pouvez utiliser MockRetrofit et NetworkBehavior pour simuler les réponses API. Voir ici une exemple de comment l'utiliser.

enfin, si vous voulez simplement tester votre service D'adaptation, le plus simple serait de créer une version simulée de celle-ci qui émet des résultats simulés pour vos tests. Par exemple, si vous avez le suivant GitHub interface de service:

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

vous pouvez alors créer le MockGitHub 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 alors utiliser le MockGitHub sur vos tests de simuler les types de réponses que vous cherchez. Pour le plein exemple, voir les implémentations de l' SimpleService et SimpleMockService de cette Rénovation exemple.

ceci étant dit, si vous devez absolument vous connecter au serveur actuel, vous pouvez configurer Retrofit pour fonctionner de manière synchrone avec un :

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

alors appliquez - le à la OkHttpClient vous utilisez lors de la construction de la Rénovation:

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

Retrofit retrofit = new Retrofit.Builder()
        .client(client)
        //Your params
        .build();
92
répondu Ricardo Lage 2016-03-12 07:45:50

La réponse est trop facile que je le pensais:

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;
}}
15
répondu AndrewS 2016-04-08 12:05:53

à moins que vous ne testiez L'API QA server, c'est une mauvaise idée pour plusieurs raisons.

  • tout D'abord vous peuplez votre base de données de production avec mauvais / faux données
  • en utilisant les ressources du serveur, quand elles peuvent être mieux utilisées pour servir demande valide

La meilleure façon d'utiliser Mockito, ou pour se Moquer de vos réponses

aussi, si vous devez tester votre API de production, le tester une fois et ajouter @Ignore annotation. De cette façon, ils ne sont pas tout le temps et ne sont pas spam votre serveur avec de fausses données et vous pouvez l'utiliser chaque fois que vous sentez que l'api ne se comporte pas correctement.

-2
répondu Akshay 2017-03-04 00:28:00