2016-03-02 16 views
42

retrofit2beta4からの実際の応答をテストできますか?私はMockitoまたはRobolecticが必要ですか?Retrofit2とMockitoまたはRobolectricによるAndroidユニットテスト

私のプロジェクトにはアクティビティがありません。ライブラリーになります。サーバーが正しく応答していることをテストする必要があります。 今、私はそのようなコードやスタックを持っている...

@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を使用して

はあなたのトンを作りますあなたが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); 
    

    また、あなたはAPIの応答をシミュレートするMockRetrofitNetworkBehaviorを使用することができます。使用方法の例は、hereを参照してください。

    最後に、Retrofit Serviceをテストしたい場合は、テストの模擬結果を出力するモックバージョンを作成するのが最も簡単です。たとえば、次のGitHubサービス・インターフェースがある場合:あなたは、その後の種類をシミュレートするために、あなたのテストに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); 
        } 
    } 
    

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

    あなたは、あなたのテストのために、次のMockGitHubを作成することができますがあなたが探している回答の完全な例については、Retrofit exampleSimpleServiceおよびSimpleMockServiceの実装を参照してください。

    このすべて、あなたは絶対に実際のサーバーに接続する必要がある場合、カスタムImmediateExecutorと同期して動作するように改修を設定することができます言った:その後、改修を構築する際に使用OkHttpClientに適用

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

    を:

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

    すべての答えは「シミュレーション」に基づいています。私が質問の話題で言ったように - 私はそれを行うことができます。私のプロジェクトはサーバーAPIで動作するライブラリです。私がテストする必要があるのは、サーバー上で変化している、私は実際の応答をテストする必要があります。 – AndrewS

    +2

    私は実際のサーバーでテストするのは理にかなっていないと思うので、私は代替案を提示しました。テストが異なるユーザーのさまざまな場所で機能し、接続の問題などを簡単にテストできないことは確実ではありません。サーバーはあなたのライブラリに属しているものではなく、そのように扱われるべきではないと私は思います。そのため、代わりにserver _responses_をテストする方が一般的に優れています。 'MockWebServer'を使うと、実サーバに接続されているかのようにテストを実行できます。あなたの図書館は違いを知らないでしょう。 –

    +2

    私は偽の成功の応答を行う場合 - 私は成功のテストを取得します。このテストのポイントは何ですか?私はちょうどサーバレスポンスが(テストによって)変更されたことを知り、新しい応答のために私のライブラリを更新する必要があります。私が偽の応答をすれば何か変わったことは決してわかりません。 – AndrewS

    -2

    QAサーバAPIをテストしていない限り、いくつかの理由で悪い考えです。

    • まずあなたは、彼らがより良い 有効な要求

    Mockitoを使用するための最良の方法を提供するために使用することができたときに、サーバーのリソースを使用して悪い/フェイク データ

  • と本番データベースを投入、またはされていますあなたの応答を模擬してください

    また、プロダクションAPIをテストする必要がある場合は、一度テストして@Ignoreアノテーションを追加してください。そうすれば、彼らは常時稼働しているわけではなく、偽のデータでサーバーを迷惑させることもなく、APIが正しく動作していないと感じるたびに使用することができます。

  • +0

    あなたのロジックがサーバーデータの更新を正しく処理していて、ローカルファイルにあなたが酷評した古いデータを正しく処理しているかどうかを確認したいときはどうでしょうか? – miroslavign

    +0

    @miroslavignあなたのロジックが常にサーバーデータの更新を正しく処理しているかどうかを確認することはどういう意味ですか?クライアントは、APIが正しく機能していることを確認する責任を負うべきではありません。また、偽のデータを使ってサーバーにスパムを送信する方法は?これらの分析のほとんどはチャートの外に出ています。これらのユニットテストのほとんどはCIの一部として実行されるためです。古いデータが心配な場合は、スタブされた応答 – Akshay

    +0

    を更新する必要があります。たとえば、サーバーのエンドポイントからのデータの解析に失敗したことを意味する毎日テストを実行したい - >意味、サーバーjsonデータの変更 - >赤旗 - >私は解析メソッド/ POJOなどを更新する必要があります。 – miroslavign

    関連する問題