簡體   English   中英

使用Retrofit2和Mockito或Robolectric進行Android單元測試

[英]Android Unit Test with Retrofit2 and Mockito or Robolectric

我可以測試一下retrofit2beta4的真實反應嗎? 我需要Mockito還是Robolectic?

我的項目中沒有活動,它將是一個庫,我需要測試服務器是否正確響應。 現在我有這樣的代碼而且卡住了......

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

我可以做出虛假的回應,但我需要測試真實。 它成功了嗎? 它的身體是否正確? 你能幫我代碼嗎?

測試真實服務器請求通常不是一個好主意。 有關主題的有趣討論,請參閱此博客文章 據作者說,使用真正的服務器是一個問題,因為:

  • 另一個可以間歇性失效的移動件
  • 需要Android域之外的一些專業知識來部署服務器並使其保持更新
  • 難以觸發錯誤/邊緣情況
  • 測試執行緩慢(仍在進行HTTP調用)

您可以使用模擬服務器(如OkHttp的MockWebServer)來模擬真實的響應結果,從而避免上述所有問題。 例如:

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

如果您需要模擬網絡延遲,可以按如下方式自定義響應:

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

或者,您可以使用MockRetrofitNetworkBehavior來模擬API響應。 在這里查看如何使用它的示例。

最后,如果您只想測試您的Retrofit服務,最簡單的方法是創建一個模擬版本,為您的測試發出模擬結果。 例如,如果您有以下GitHub服務接口:

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

然后,您可以為測試創建以下MockGitHub

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

然后,您可以在測試中使用MockGitHub來模擬您要查找的各種響應。 有關完整示例,請參閱此Retrofit示例SimpleServiceSimpleMockService的實現。

說完這一切之后,如果你絕對必須連接到實際的服務器,你可以設置Retrofit與自定義ImmediateExecutor同步工作:

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

然后將其應用於構建Retrofit時使用的OkHttpClient

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

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

答案太容易了:

使用CountDownLatch使您的測試等到調用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;
}}

除非您正在測試QA服務器API,否則出於幾個原因這是一個壞主意。

  • 首先,您使用壞/假數據填充生產數據庫
  • 使用服務器資源時,它們可以更好地用於服務有效請求

使用Mockito的最佳方式,或模擬您的回復

此外,如果您必須測試生產API,請測試一次並添加@Ignore注釋。 這樣他們就不會一直運行,也不會使用假數據向您的服務器發送垃圾郵件,只要您覺得api行為不正確就可以使用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM