EspressoでNavigationView関連のテストをするときは、WebViewが表示されていてはいけない

#0. 前提

AndroidStudio2.1.1
Espesso 2.2.1
Target / Compile SDK 23
MinSDK 16

```app/build.gladle
dependencies {
...
    testCompile 'junit:junit:4.12'
    testCompile 'org.json:json:20140107'
    androidTestCompile 'com.android.support.test:runner:0.4.1'
    androidTestCompile 'com.android.support.test:rules:0.4.1'
    androidTestCompile 'com.android.support:recyclerview-v7:23.3.0'
    androidTestCompile 'com.android.support:support-v4:23.3.0'
    androidTestCompile 'com.android.support:support-annotations:23.3.0'
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
    androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2.1'

    compile 'com.android.support:recyclerview-v7:23.3.0'
    compile 'com.android.support:support-v4:23.3.0'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'
...
}
```

#1. 遭遇した現象

Espressoで、NavigationViewの開閉をテストしようとして、以下のようにテストを記述。

```java:MainActivityTest.java

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {
    MainActivity mActivity;

    @Rule
    public ActivityTestRule<MainActivity> activityTestRule =
            new ActivityTestRule<>(MainActivity.class);

    @Before
    public void setUp() throws Exception {
        mActivity = activityTestRule.getActivity();
    }

    @Test
    public void サイドメニュー開閉() {
        Espresso.onView(withId(R.id.drawer_layout)).check(matches(DrawerMatchers.isClosed()));
        Espresso.onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());　 // (*)
        Espresso.onView(withId(R.id.drawer_layout)).check(matches(DrawerMatchers.isOpen()));
        Espresso.onView(withId(R.id.drawer_layout)).perform(DrawerActions.close());
        Espresso.onView(withId(R.id.drawer_layout)).check(matches(DrawerMatchers.isClosed()));
        // 戻るボタンで閉じるのを確認
        Espresso.onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
        Espresso.pressBack();
        Espresso.onView(withId(R.id.drawer_layout)).check(matches(DrawerMatchers.isClosed()));
    }
```

そしたら、(*)の部分でタイムアウトみたいなエラーが出ました。

```
AppNotIdleException: Looped for XXXX iterations over 60 SECONDS. The following Idle Conditions failed . 
```

#2. 構成

MainActivityの構成
+ActionBar
+Toolbar
+TabLayout
+ViewPager
+NavigationView

ViewPagerで表示するFragmentが、WebView表示。
で、onResume/onPauseに以下を記述済み。

```java:WebFragment.java

import android.support.v4.app.Fragment;
...

public class WebFragment extends Fragment{
...

    @Override
    public void onResume() {
        super.onResume();
        webView.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        webView.onPause();
    }

}
```

#3. 原因

```
AppNotIdleException: Looped for XXXX iterations over 60 SECONDS. The following Idle Conditions failed . 
```

このエラーの原因は、要するに、MainThreadがひたすらビジーになってるよ、ということらしい。
MainThreadがひたすらビジーと言うことは、「画面がひたすら再描画されている」と考えていい。
でも、アニメーションしているViewはないし、Progressも消している。
そこで、開発者メニューの「画面の更新を表示」にチェックを入れて、アプリを通常起動し（テストでは無く）、NavigationViewを表示させてみた。

※ただし、このオプションが有効だと、画面が激しく点滅するので、ご注意されたし。

結果、NavigationView表示中はひたすら点滅・・・。は、激しい。目が痛い。
そこで、どのViewが問題なのかを調査するべく、、、いや最初から、WebViewを疑ってましたがね。（とはいえ、Tab+ViewPagerかも？とも疑ってたかな。）

とりあえず、新規プロジェクトで「Navigation Drawer Activity」を選択してデフォルトのままで起動してみました。

問題なし。
少し点滅しますが、じきに収まります。

MainActivityにWebViewを追加して、再度起動。

はい、延々と点滅し始めました。

犯人は、WebView。

もう一つ。

Navigationが開いたときに、WebViewを非表示にして、閉じたらまた表示されるようにして見ました。

点滅しなくなりました。

というわけで、

**NavigationViewを表示するときに、WebViewが表示されていてはいけない(Visibility==View.VISIBLEであってはいけない)**

という結論です。

#4. 対策

困りましたね。まあテスト時だけ、以下のようすれば、とりあえず回避出来ます。

```MainActivity.java

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
        drawerLayout.addDrawerListener(this);
        ...
    }

    @Override
    public void onDrawerOpened(View drawerView) {
        if (Debug.isTest) {
            webView.setVisibility(View.INVISIBLE);
        }
    }

    @Override
    public void onDrawerClosed(View drawerView) {
        if (Debug.isTest) {
            webView.setVisibility(View.VISIBLE);
        }  
    }
```

MainActivityTest.javaに以下を追記。

```java:MainActivityTest.java
    @BeforeClass
    public static void initClass() {
        Debug.isTest = true;
    }
```

Debugクラスは適当にクラス作って置いて下さい。
心配だったらapp/src/debugとapp/src/releaseに置き分けておくといいかもですね。

これだとNavigationView表示時に裏画面が真っ黒になったりしますが（テーマにもよるかな)、まあテスト時だけなので・・・

ちなみに、私は横着してデバッグ用画面表示時(サーバーアクセスしないためのローカルhtmlを読む画面)にそうするようにしちゃったので、JUnit以外でも目撃される可能性があったので、ちょっと見た目をいじりました。

(1)NavigationViewが開いた時にWebViewのDrawingCacheを取得してImageViewに貼り付けて、そのImageViewをsetVisibility(View.VISIBLE)

(2)NavigationViewが閉じた時にそのImageViewをsetVisibility(View.INVISIBLE)

とやりました。
JUnit通過させるためだけなら不要ですね。

これで、無事、サイドメニュー開閉テストが通過しました。
やれやれ。