2016-03-02 67 views
42

我可以测试retrofit2beta4的真实响应吗?我需要Mockito还是Robolectic?安卓单元测试使用Retrofit2和Mockito或Robolectric

我没有活动在我的项目中,它将是一个库,我需要测试的是服务器正确响应。 现在我有这样的代码和卡...

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

我可以做的假的反应,但我需要测试实际的。它成功了吗?它的身体是否正确? 你可以帮助我的代码?

回答

15

答案是太容易了,比我预期:

使用CountDownLatch让你的T请等待,直到您致电countDown()

public class SimpleRetrofitTest { 

private static final String login = "[email protected]"; 
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; 
}} 
85

测试真实的服务器请求通常不是一个好主意。有关该主题的有趣讨论,请参阅this blog post。据笔者,使用您的真实服务器是一个问题,因为:

  • 另一个运动件,可以间歇性地失败
  • 所需的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响应。请参阅here如何使用它的示例。

最后,如果你只是想测试你的改进服务,最简单的方法是创建一个模拟版本,发布模拟测试结果。例如,如果您有以下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上的测试,以模拟种您正在寻找的回复。有关完整示例,请参阅的SimpleServiceSimpleMockService的实现。

说了这么多,如果你绝对必须连接到实际的服务器,你可以设置改造与定制ImmediateExecutor同步工作:

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

然后将它应用到OkHttpClient您在构建改造时使用:

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

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

所有的答案都基于“模拟”。正如我在问题上所说的 - 我可以做到这一点。我的项目是一个可以与服务器API协同工作的库。我需要测试的唯一事情就是在服务器上进行更改,我需要测试真实的响应。 – AndrewS

+2

我提供了替代方案,因为我认为在真实服务器上测试是没有意义的。您无法确定测试将在不同用户的不同位置工作,您无法轻松测试连接问题等等。服务器不属于你的图书馆,我认为不应该这样对待。这就是为什么通常更好地测试服务器_responses_的原因。如果你使用'MockWebServer',你可以运行你的测试,就像连接到真实的服务器一样。你的图书馆不知道其中的差别。 –

+2

如果我做出假冒成功的回应 - 我会得到成功的考验。这个测试有什么意义?我只需要知道服务器响应何时更改(通过测试),以更新我的库以获取新响应。如果我做出虚假的回应,我永远不会知道有什么改变。 – AndrewS

-2

除非您正在测试QA服务器API,否则由于多种原因,这是一个坏主意。

  • 首先,这样填充坏/假 数据生产数据库
  • 利用服务器资源,当他们可以更好地用来服务 有效的请求

最好的方式来使用的Mockito,或嘲笑你的回应

另外,如果你必须测试你的生产API,测试一次并添加@Ignore注释。这样,它们不会一直运行,也不会将虚假数据发送给服务器,只要您觉得api的行为不正确,就可以使用它。

+0

如果您想检查您的逻辑是否正确处理了不断更新的服务器数据,而不是您在本地文件中嘲笑的陈旧数据,那么该怎么办? – miroslavign

+0

@miroslavign不知道你的意思是“检查你的逻辑是否正确处理了不断更新的服务器数据”。客户不应该负责确保API正常工作。以及应用程序如何用假数据发送服务器垃圾邮件?分析失败了,因为这些单元测试大部分是作为CI的一部分运行的。例如,如果您担心陈旧的数据,您应该更新您的存根响应 – Akshay

+0

例如,我希望每天都运行测试检查来自服务器端点的数据解析是否失败 - >意思是,服务器json数据更改 - >红色标志 - >我应该更新我的解析方法/ POJO或其他。 – miroslavign

相关问题