2016-03-02 103 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

相關問題