Activityの終了コードをテストする

リストビューで複数の項目から任意のものを選択させ、その選択した値を呼び出し元に返す。

そんな、「Activityを終了時にIntent#putExtraして返すようなサブ画面」を作ることは多いと思いますが、そういった画面がちゃんとIntentに想定した値をセットできているかのテストは、以下の理由で単純には行きません。

1.ActivityUnitTestCaseならば、遷移したActivityやresultCodeが取れるが、UI操作のテストは出来ない
2.ActivityInstrumentationTestCase2は、UI操作はもちろん、Activityの遷移も何とかテストできるが、setResultした値がそのままでは取得できない

解法としては、リフレクションを使うしかないようです。

ということで、リストのアイテム選択部分も併せて自分用メモとしておいときます。

```java:FileListActivity.java
public class FileListActivity extends Activity {
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// タイトルバーのプログレスバーを設定可能にする
		requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

		setContentView(R.layout.filelist);

		mListView.setOnItemClickListener(
			new AdapterView.OnItemClickListener() {
			/**
			 * リストアイテムクリック処理
			 */
			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				File file = getFile(id);
				// アイテムクリック処理
				onFinish(file);
			}
		}

		// リストの初期化
		;//(省略)
	}

	/**
	 * アクティビティ終了処理
	 *
	 * @param file
	 *            選択されたファイルorディレクトリ.null可
	 */
	protected void onFinish(File file) {
		Intent result = new Intent();
		if (file != null) {
			result.putExtra("file", file.getName());
			setResult(RESULT_OK, result);
		} else {
			setResult(RESULT_FIRST_USER);
		}
		// この画面を終了
		finish();
	}
}

```


```java:TestFileListActivity.java
public class TestFileListActivity extends ActivityInstrumentationTestCase2<FileListActivity> {
	FileListActivity mActivity = null;

    public TestFileListActivity(){
        super(FileListActivity.class);
    }
    /** リストのアイテムをタップさせる */
    private void touchListItem(final int listIndex) throws Throwable{
    	runTestOnUiThread(new Runnable() {
    	    @Override
    	    public void run() {
    	    	ListView list = (ListView) mActivity.findViewById(R.id.FileListView);
    	    	list.setSelection(listIndex);
    	    }
    	});
     	sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
     	getInstrumentation().waitForIdleSync();
    }
	/** Activity終了コード判定 */
	protected Intent assertFinishCalledWithResult(int resultCode) {
		try {
			Field f = Activity.class.getDeclaredField("mResultCode");
			f.setAccessible(true);
			int actualResultCode = (Integer)f.get(getActivity());
			assertEquals(resultCode, actualResultCode);
			f = Activity.class.getDeclaredField("mResultData");
			f.setAccessible(true);
			return (Intent)f.get(getActivity());
		} catch (NoSuchFieldException e) {
			throw new RuntimeException("Looks like the Android Activity class has changed it's   private fields for mResultCode or mResultData.  Time to update the reflection code.", e);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	/**  テスト */
	public void test007_touch_file() throws Throwable {
		String pathname = Environment.getExternalStorageDirectory().getAbsolutePath();
		Intent i = new Intent();
		i.putExtra("dir", pathname);
		
		setActivityIntent(i);
		mActivity = getActivity();
		
		// ファイルをタップ
		touchListItem(3);
		
		// Activity終了しているはず
		ListView list = (ListView) mActivity.findViewById(R.id.FileListView);
		b = list.isShown();
		assertFalse(b);
		
		// 終了インテントの確認
		i = assertFinishCalledWithResult(Activity.RESULT_OK);
		String s = i.getStringExtra("file");
		assertEquals("readsample1.csv", s);
	}
}
```

参考サイト：
http://stackoverflow.com/questions/5569830/get-result-from-an-activity-after-finish-in-an-android-unit-test