Instrumentationによるユニットテストでは直接ビューを触ってはいけない

ActivityInstrumentationTestCase2クラスなどを使用してActivityをテストする際に、うっかりテスト中で

Button button = (Button)activity.findViewById(R.id.Button01);
button.performClick();

などと書いてしまうと

android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRoot.checkThread(ViewRoot.java:2683)
at android.view.ViewRoot.playSoundEffect(ViewRoot.java:2472)
at android.view.View.playSoundEffect(View.java:8306)
at android.view.View.performClick(View.java:2363)
:

と、思いっきり怒られる。

これはUIスレッド以外のスレッドでビューを操作することを禁じているためで、このケースではInstrumentationによるテストはテスト対象のアプリケーションを外側から起動しており、当然UIスレッド外となる。
Java(JFC/Swing)や.NET C#(Windows Forms)等と同様に、シングルスレッドモデルを使用しているAndroid SDKでは当たり前のことなのだが、ついつい忘れがちだ。

どうするのが正しいか?

1. Handlerを使用する

Android SDKではマルチスレッド下でGUIを操作するために、Handlerクラスが用意されている。

private Handler handler = new Handler();
private Activity activity;

protected void setUp() throws Exception {
    super.setUp();
    activity = this.getActivity();
}
public test_click_button() {
    handler.post(new Runnable(){
        @Override
        public void run() {
            Button button = (Button)activity.findViewById(R.id.Button01);
            button.performClick();
        }
    });
}

Handlerによって、GUIへの操作はUIスレッドと同期される。
なお、Handlerのインスタンスはこの場合フィールドである必要がある。メソッドのスコープ中にRunnableが実行されるとは限らないためだ。
2. Activity#runOnUiThreadメソッドを使用する

public test_click_button() {
    activity.runOnUiThread(new Runnable(){
         @Override
        public void run() {
            Button button = (Button)activity.findViewById(R.id.Button01);
            button.performClick();
        }
    });
}

元々、Activityは内部にHandlerを所有しており、それを使うことで1.と同様の処理を実現できる。
こちらは内部でRunnableの実行の同期が必要か否かを判定しており(同期不要であればHandlerを介さず実行される)、従ってActivityを使用することが判っているのであれば、こちらを使うのがお勧めだ。