Espresso で アイドリング

espresso

Espresso は以下の非同期処理は考慮してくれるようですが.

- メッセージキューを利用したUIイベント
- デフォルト AsyncTask のスレッドプールを利用したタスク

Square Island: Espresso: Custom Idling Resource

これらに該当しない処理でも, テスト実行を「あるタイミング」まで待たせたいときがありますよね?

カスタムした「IdlingResource」を使ってみましょう.

Espresso Idling Resource

ここで書かれているアプローチとしては2つ.

Counting running jobs: When a job starts, increment a counter. When it finishes, decrement it. The app is idle if the counter is zero. This approach is very simple and accounts for most situations. CountingIdlingResource does exactly this.

Querying state: It might be more reliable to ask a work queue or an HTTP client (or whatever is doing the background work) if it is busy. If the state is exposed, implementing an Idling Resource is trivial.

これらのうち, 汎用的に使えるジョブカウンターを利用した方法を, Googleサンプルを眺めつつ手順整理しておきます.

Android Testing Codelab

1. IdlingResource ユーティリティの作成

アイドリング向けのユーテリティを作成します.
そのまま2つのクラスを利用してもいいかもしれません.

EspressoIdlingResource.java at master · googlecodelabs/android-testing

SimpleCountingIdlingResource.java at master · googlecodelabs/android-testing

2. テスト対象の Activity に記述

テスト対象となる Activity にテスト時に利用するメソッドを記述しておきます.
テスト時にはこのメソッドを利用して, 先ほどのユーティリティを利用登録します.


    @VisibleForTesting
    public IdlingResource getCountingIdlingResource() {
        return EspressoIdlingResource.getIdlingResource();
    }

AddNoteActivity.java at master · googlecodelabs/android-testing

NotesActivity.java at master · googlecodelabs/android-testing

3. 「待たせる」処理の記述

Presenter や View などのテスト対象クラス内にアイドリングの利用タイミングを記述しておきます.


EspressoIdlingResource.increment(); 


EspressoIdlingResource.decrement(); 

カウンターを増減しながらアイドリングを操作します.
カウンターが0になると処理が再開されます.


    @Override
    public void loadNotes(boolean forceUpdate) {
        mNotesView.setProgressIndicator(true);
        if (forceUpdate) {
            mNotesRepository.refreshData();
        }

        // The network request might be handled in a different thread so make sure Espresso knows
        // that the app is busy until the response is handled.
        EspressoIdlingResource.increment(); // App is busy until further notice

        mNotesRepository.getNotes(new NotesRepository.LoadNotesCallback() {
            @Override
            public void onNotesLoaded(List<Note> notes) {
                EspressoIdlingResource.decrement(); // Set app as idle.
                mNotesView.setProgressIndicator(false);
                mNotesView.showNotes(notes);
            }
        });
    }

AddNoteFragment.java at master · googlecodelabs/android-testing

NotesPresenter.java at master · googlecodelabs/android-testing

4. テスト内で登録する

テスト対象Activityに記述したメソッドを利用してテストコードへ登録します
アイドリング処理がテスト時に反映されます.


    @Before
    public void registerIdlingResource() {
        Espresso.registerIdlingResources(
                mAddNoteIntentsTestRule.getActivity().getCountingIdlingResource());
    }

    @After
    public void unregisterIdlingResource() {
        Espresso.unregisterIdlingResources(
                mAddNoteIntentsTestRule.getActivity().getCountingIdlingResource());
    }

AddNoteScreenTest.java at master · googlecodelabs/android-testing

まとめ

テストにかかるコストがただの自己満足で終わらないようにしたいです.

JakeWharton/okhttp-idling-resource: An Espresso IdlingResource for OkHttp.

PSA: Dont Use Espresso Idling Resources like Google does · Philosophical Hacker


関連ワード:  AndroidAndroidStudioGradleおすすめアプリツール初心者開発