web-dev-qa-db-ja.com

Retrofit API呼び出しを単体テストする方法

可能なすべてのコードのチャンクに対してユニットテストケースを統合しようとしています。しかし、API呼び出しのテストケースを追加するときに問題に直面していますretrofitで作成

JUnitコンパイラは、決して実行しませんCallBack関数のコード

テスト目的ですべてのAPI呼び出し同期を作成する別のオプションがありますが、これは私のアプリのすべてのケースで可能というわけではありません。

これをどうやって整理できますか?何らかの方法でAPI呼び出しにテストケースを追加する必要があります。

52
AabidMulani

Mockito、Robolectric、およびHamcrestライブラリを使用して、レトロフィットコールバックをテストします。

まず、モジュールのbuild.gradleにlibスタックをセットアップします。

dependencies {
    testCompile 'org.robolectric:robolectric:3.0'
    testCompile "org.mockito:mockito-core:1.10.19"
    androidTestCompile 'org.hamcrest:hamcrest-library:1.1'
}

Jourプロジェクトのグローバルbuild.gradleで、buildscript依存関係に次の行を追加します。

classpath 'org.robolectric:robolectric-gradle-plugin:1.0.1'

次に、Android Studioで[Build Variants]メニューに入り(すばやく検索するには、Ctrl + Shift + Aを押して検索します)、[Test Artifact]オプションを[Unit Tests]に切り替えます。 Androidスタジオは、テストフォルダーを(androidTestではなく)「com.your.package(test)」に切り替えます。

OK。セットアップが完了しました。いくつかのテストを作成します。

たとえば、RecyclerViewなどのアダプターに入れる必要のあるオブジェクトのリストを取得するためのレトロフィットAPI呼び出しがあるとします。呼び出しが成功すると、アダプターが適切なアイテムで満たされるかどうかをテストします。これを行うには、Retrofitインターフェースの実装を切り替えて、モックを使用して呼び出しを行い、Mockito ArgumentCaptorクラスを利用していくつかの偽の応答を行う必要があります。

@Config(constants = BuildConfig.class, sdk = 21,
    manifest = "app/src/main/AndroidManifest.xml")
@RunWith(RobolectricGradleTestRunner.class)
public class RetrofitCallTest {

    private MainActivity mainActivity;

    @Mock
    private RetrofitApi mockRetrofitApiImpl;

    @Captor
    private ArgumentCaptor<Callback<List<YourObject>>> callbackArgumentCaptor;

    @Before
    public void setUp() {            
        MockitoAnnotations.initMocks(this);

        ActivityController<MainActivity> controller = Robolectric.buildActivity(MainActivity.class);
        mainActivity = controller.get();

        // Then we need to swap the retrofit api impl. with a mock one
        // I usually store my Retrofit api impl as a static singleton in class RestClient, hence:
        RestClient.setApi(mockRetrofitApiImpl);

        controller.create();
    }

    @Test
    public void shouldFillAdapter() throws Exception {
        Mockito.verify(mockRetrofitApiImpl)
            .getYourObject(callbackArgumentCaptor.capture());

        int objectsQuantity = 10;
        List<YourObject> list = new ArrayList<YourObject>();
        for(int i = 0; i < objectsQuantity; ++i) {
            list.add(new YourObject());
        }

        callbackArgumentCaptor.getValue().success(list, null);

        YourAdapter yourAdapter = mainActivity.getAdapter(); // Obtain adapter
        // Simple test check if adapter has as many items as put into response
        assertThat(yourAdapter.getItemCount(), equalTo(objectsQuantity));
    }
}

テストクラスを右クリックし、実行をクリックして、テストを続行します。

以上です。 Robolectric(robolectric gradleプラグイン)とMockitoを使用することを強くお勧めします。これらのライブラリにより、Androidアプリのテストがずっと簡単になります。この方法は、次の ブログ投稿 から学びました。また、 this answer を参照してください。

Update:RxJavaでRetrofitを使用している場合は、 他の回答 もチェックしてください。

25
maciekjanusz

。enqueue()の代わりに。execute()を使用すると、実行が同期されるため、テストは正常に実行できます3つの異なるライブラリをインポートし、コードを追加するか、ビルドバリアントを変更する必要があります。

好む:

public class LoginAPITest {

    @Test
    public void login_Success() {

        APIEndpoints apiEndpoints = RetrofitHelper.getTesterInstance().create(APIEndpoints.class);

        Call<AuthResponse> call = apiEndpoints.postLogin();

        try {
            //Magic is here at .execute() instead of .enqueue()
            Response<AuthResponse> response = call.execute();
            AuthResponse authResponse = response.body();

            assertTrue(response.isSuccessful() && authResponse.getBearer().startsWith("TestBearer"));

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
19
Adam Varhegyi
  • JUnitフレームワークは、応答が取得される前に実行のメインスレッドが終了するため、CallBack関数のコードを実行しません。以下に示すように、CountDownLatchを使用できます。

    @Test
    public void testApiResponse() {
        CountDownLatch latch = new CountDownLatch(1);
        mApiHelper.loadDataFromBackend(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                System.out.println("Success");
                latch.countDown();
            }
    
            @Override
            public void onFailure(Call call, Throwable t) {
                System.out.println("Failure");
                latch.countDown();
            }
        });
    
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } 
    }
    
  • この テストサンプル も役立つ場合があります。

  • 私のアドバイスは、AndroidアプリでAPIレスポンスのテストを実行することではありません。これには多くの外部 ツール があります。
3
Islam Salah

すでにレトロフィット2.0と安静時のrxをカプセル化している場合

open class BaseEntity<E> : Serializable {
    /*result code*/
    var status: Int = 0
    /**data */
    var content: E? = null
}

およびサーバーAPIリクエストのような

@GET(api/url)
fun getData():Observable<BaseEntity<Bean>>

サービスは1つの同期要求のみをコールバックします

val it = service.getData().blockingSingle()
assertTrue(it.status == SUCCESS_CODE)
1
shuabing