使用Retrofit2和Mockito或Robolectric的Androidunit testing

我可以testingretrofit2beta4的真实反应吗? 我需要Mockito还是Robolectic?

我没有在我的项目活动,这将是一个图书馆,我需要testing是服务器响应正确。 现在我有这样的代码卡住了…

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

我可以做出假的回应,但我需要testing真实。 成功了吗? 它的身体是否正确? 你能帮我用代码吗?

testing真正的服务器请求通常不是一个好主意。 看到这个博客文章的主题有趣的讨论。 据作者说,使用真实的服务器是一个问题,因为:

  • 另一个可以间歇性失败的动作片
  • 需要一些Android领域以外的专家来部署服务器并保持更新
  • 很难触发错误/边缘情况
  • 缓慢的testing执行(仍在进行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(); } 

如果您需要模拟networking延迟,您可以按如下方式自定义您的响应:

 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响应。 在这里看到一个如何使用它的例子。

最后,如果你只是想testing你的Retrofit服务,最简单的方法就是创build一个模拟版本,为你的testing发出模拟结果。 例如,如果您有以下GitHub服务界面:

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

然后,您可以为您的testing创build以下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); } } 

然后,您可以在testing中使用MockGitHub来模拟您正在查找的响应types。 有关完整的示例,请参阅此Retrofit示例的SimpleService和SimpleMockService的实现。

话虽如此,如果您绝对必须连接到实际的服务器,您可以将Retrofit设置为与自定义ImmediateExecutor同步工作:

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

然后将其应用于构buildRetrofit时使用的OkHttpClient

 OkHttpClient client = OkHttpClient.Builder() .dispatcher(new Dispatcher(new ImmediateExecutor())) .build(); Retrofit retrofit = new Retrofit.Builder() .client(client) //Your params .build(); 

答案是比我想象的容易:

使用CountDownLatch让你的testing等到你调用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; }} 

除非您正在testingQA服务器API,否则有几个原因是不好的主意。

  • 首先,您正在使用错误/假数据填充生产数据库
  • 使用服务器资源的时候,可以更好地用于服务有效的请求

使用Mockito的最好方法,或者模拟你的回应

另外,如果您必须testing您的生产API,请testing一次并添加@Ignore注释。 这样,它们不会一直运行,也不会使用伪造的数据将您的服务器垃圾邮件,只要您感觉api的行为不正确,就可以使用它。