Activity

引数付きActivityの起動について

<問題現象> JunitプロジェクトにてAndroidのActivityをテストするために、 Activityを起動する場合は、引数がありましたら、下記のソースでActivityを起動できていません。 mActivity = getActivity();

1
2
3
4
    protected void setUp() throws Exception {
        super.setUp();
        mActivity = getActivity();  
}

%{color:red}単に、引数なしActivityを起動でき、引数付きActivityはできません。%

<対応方法> この問題を解決するために、下記のソースを検証されました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
    protected void setUp() throws Exception {
        super.setUp();
        //PropertyActivityは、テスト対象となります。
        //テストしたいActivityの名前を差し替えてください。
        mInstrumentation = getInstrumentation();
        mMonitor = mInstrumentation.addMonitor(
                PropertyActivity.class.getName(), null, false);

        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setClassName(mInstrumentation.getTargetContext(),
                PropertyActivity.class.getName());
        long id = 16;
        intent.putExtra(C.bundle.DOC_ID, id); //Activityの引数です。

        mInstrumentation.startActivitySync(intent);
        mActivity = (PropertyActivity) mInstrumentation
                .waitForMonitorWithTimeout(mMonitor, 5);
    }

  • 参照ソースでは、PropertyActivityをテスト対象となっています。
  • テストActivityに引数を渡す場合は、Activityを起動すると同じように  intentを使います。
  • パラメーターの渡しは、putExtraメソッドで行います。

複数の同じActivityが起動されるについて

<問題現象> 一つの新しいActivityを起動して、しかもIntentによりデータの付きの場合、 テストコードで、一つのIntentにより一つの新しいActivityを起動します。("引数付きActivityの起動について":http://czuft-redmine:3000/projects/documents/wiki/%E5%BC%95%E6%95%B0%E4%BB%98%E3%81%8DActivity%E3%81%AE%E8%B5%B7%E5%8B%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

初めてのActivityが取得されることができますが、 再度起動したいActivityが取得されることが難しいので、 下記のソースでActivityを起動できていません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Intent intent1 = new Intent(getInstrumentation().getContext(),PropertyActivityTest.class);

intent1.putExtra(C.bundle.DATA_TYPE, false);
intent1.putExtra(C.bundle.DOC_ID, id);
setActivityIntent(intent1);
mActivity = getActivity();

mInstrumentation.waitForIdleSync();

mActivity.runOnUiThread(new Runnable() {

    @Override
    public void run() {
        //UIを扱う
    }
});
mActivity.finish();

Intent intent2 = new Intent(getInstrumentation().getContext(),PropertyActivityTest.class);

long id = 1;
intent2.putExtra(C.bundle.DATA_TYPE, true);
intent2.putExtra(C.bundle.DOC_ID, id);

setActivityIntent(intent2);
mActivity = getActivity();

mInstrumentation.waitForIdleSync();

mActivity.runOnUiThread(new Runnable() {

    @Override
    public void run() {
        //UIを扱う
    }
});
mActivity.finish();

上記のソースで新しいActivityを起動できていませんが、行26でmActivityがまだ初めてのActivityです。

<対応方法> この問題を解決するために、下記のソースを検証されました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Intent intent1 = new Intent(getInstrumentation().getContext(),PropertyActivityTest.class);

intent1.putExtra(C.bundle.DATA_TYPE, false);
intent1.putExtra(C.bundle.DOC_ID, id);
setActivityIntent(intent1);
mActivity = getActivity();

mInstrumentation.waitForIdleSync();

mActivity.runOnUiThread(new Runnable() {

    @Override
    public void run() {
        //UIを扱う
    }
});
mActivity.finish();

//必要がある
setActivity(null);
//必要がある

Intent intent2 = new Intent(getInstrumentation().getContext(),PropertyActivityTest.class);

long id = 1;
intent2.putExtra(C.bundle.DATA_TYPE, true);
intent2.putExtra(C.bundle.DOC_ID, id);

setActivityIntent(intent2);
mActivity = getActivity();

mInstrumentation.waitForIdleSync();

mActivity.runOnUiThread(new Runnable() {

    @Override
    public void run() {
        //UIを扱う
    }
});
mActivity.finish();

ダイアログのテストについて

ダイアログを呼び出してテストしたい場合は、 画面と同じように、下記のソースでダイアログのコントロールの値をセットできなくなっています。 また、ダイアログ画面上のボタンに対してクリックテストもできなくなる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
mActivity.runOnUiThread(new Runnable() {

    @Override
    public void run() {
        LayoutInflater factory = LayoutInflater.from(mActivity);
        final View markView = factory.inflate(R.layout.dialog_setting_mark, null);
        markView.isClickable();
        TextView textViewTag1 = (TextView) markView.findViewById(R.id.textViewSettingMark1DialogName);
        textViewTag1.setText("* :");

        TextView textViewTag2 = (TextView) markView.findViewById(R.id.textViewSettingMark2DialogName);
        textViewTag2.setText("△ :");

        TextView textViewTag3 = (TextView) markView.findViewById(R.id.textViewSettingMark3DialogName);
        textViewTag3.setText("# :");

        TextView textViewTag4 = (TextView) markView.findViewById(R.id.textViewSettingMark4DialogName);
        textViewTag4.setText("$ :");

        TextView textViewTag5 = (TextView) markView.findViewById(R.id.textViewSettingMark5DialogName);
        textViewTag5.setText("レ :");

        Button buttonMarkRight = (Button) markView.findViewById(R.id.buttonSettingMarkDialogRight);
        buttonMarkRight.performClick();

        assertEquals("* :", textViewTag1.getText().toString());
        assertEquals("△ :", textViewTag2.getText().toString());
        assertEquals("# :", textViewTag3.getText().toString());
        assertEquals("$ :", textViewTag4.getText().toString());
        assertEquals("レ :", textViewTag5.getText().toString());
    }

        });

スレッドで、Activityのダイアログをテストできていませんでした。

・上記の通り、ダイアログをテストするために、 サードパーティパッケージ{{fn(Solo,サードパーティパッケージrobotium-soloとなっています)}}を使う必要になりそうです。 下記の例に参照してください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public void testSettingShow() throws Exception {
        TextView mainTitleTextView = (TextView) solo.getView(R.id.main_titlespace_title);
        assertEquals("Paper Writer / Finder", mainTitleTextView.getText().toString());
        TextView settingShowTextView = (TextView) solo.getView(R.id.setting_show_textview);
        assertEquals("動作", settingShowTextView.getText().toString());
        solo.clickOnView(settingShowTextView);
        TextView markSettingTextView = (TextView) solo.getView(R.id.marksetting_textview);
        assertEquals("マークの設定", markSettingTextView.getText().toString());
        solo.clickOnView(markSettingTextView);

        TextView markDialogTitleTextView = (TextView) solo.getView(R.id.textViewSettingMarkDialogTitle);
        assertEquals("マークの設定", markDialogTitleTextView.getText().toString());

        TextView textViewTag1 = (TextView) solo.getView(R.id.textViewSettingMark1DialogName);
        TextView textViewTag2 = (TextView) solo.getView(R.id.textViewSettingMark2DialogName);
        TextView textViewTag3 = (TextView) solo.getView(R.id.textViewSettingMark3DialogName);
        TextView textViewTag4 = (TextView) solo.getView(R.id.textViewSettingMark4DialogName);
        TextView textViewTag5 = (TextView) solo.getView(R.id.textViewSettingMark5DialogName);

        assertEquals("* :", textViewTag1.getText().toString());
        assertEquals("△ :", textViewTag2.getText().toString());
        assertEquals("# :", textViewTag3.getText().toString());
        assertEquals("$ :", textViewTag4.getText().toString());
        assertEquals("レ :", textViewTag5.getText().toString());

        EditText editTextMark1Content = (EditText) solo.getView(R.id.editTextSettingMark1DialogName);
        EditText editTextMark2Content = (EditText) solo.getView(R.id.editTextSettingMark2DialogName);
        EditText editTextMark3Content = (EditText) solo.getView(R.id.editTextSettingMark3DialogName);
        EditText editTextMark4Content = (EditText) solo.getView(R.id.editTextSettingMark4DialogName);
        EditText editTextMark5Content = (EditText) solo.getView(R.id.editTextSettingMark5DialogName);

        assertEquals("重要", editTextMark1Content.getText().toString());
        assertEquals("やること", editTextMark2Content.getText().toString());
        assertEquals("アイデア", editTextMark3Content.getText().toString());
        assertEquals("確認事項", editTextMark4Content.getText().toString());
        assertEquals("課題", editTextMark5Content.getText().toString());

        solo.clearEditText(editTextMark1Content);
        solo.enterText(editTextMark1Content, "じゅうよう");
        solo.clickOnButton("OK");

        solo.clickOnView(markSettingTextView);
        assertEquals("じゅうよう", editTextMark1Content.getText().toString());
        solo.clickOnButton("キャンセル");
    }
  • Solo:サードパーティパッケージrobotium-soloとなっています

画面テスト常用技法について

下記のハードコピーや、画面などをテストするために、 入力領域への値入力や、ボタンなどを押すことなでの操作はよく瀕発しますので 常に使える方法として、整理して記述しています。

  • "値入力":http://czuft-redmine:3000/projects/documents/wiki/%E7%94%BB%E9%9D%A2%E3%83%86%E3%82%B9%E3%83%88%E5%B8%B8%E7%94%A8%E6%8A%80%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6#値入力
  • "ボタンクリック":http://czuft-redmine:3000/projects/documents/wiki/%E7%94%BB%E9%9D%A2%E3%83%86%E3%82%B9%E3%83%88%E5%B8%B8%E7%94%A8%E6%8A%80%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6#ボタンクリック
  • "フォカスリクエストとクリア":http://czuft-redmine:3000/projects/documents/wiki/%E7%94%BB%E9%9D%A2%E3%83%86%E3%82%B9%E3%83%88%E5%B8%B8%E7%94%A8%E6%8A%80%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6#フォカスリクエストとクリア
  • "ビューチェック":http://czuft-redmine:3000/projects/documents/wiki/%E7%94%BB%E9%9D%A2%E3%83%86%E3%82%B9%E3%83%88%E5%B8%B8%E7%94%A8%E6%8A%80%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6#ビューチェック
  • 他<後日追記>

値入力

入力領域(EditTextなど)に値を入力してテストを検証するときに、 下記の方法で参照できます。

  1. 画面上のコントロールのIDを取得してから、{{fn(Solo,サードパーティパッケージrobotium-soloとなっています)}}のenterTextメソッドを利用して値の入力をできること
1
2
3
EditText editTextPasswordContent = (EditText) solo.getView(R.id.editTextSettingPasswordDialogName);
solo.enterText(editTextPasswordContent, "123456");
assertEquals("123456", editTextPasswordContent.getText().toString());
  1. 画面上のコントロールを取得してフォカスを取ってから、  Android自身のsendKeysメソッドを利用して値の入力をできること
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    View view = (View) mActivity.findViewById(R.id.textViewsearch);
    
    mActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            view.requestFocus();
        }
    });
    mInstrumentation.waitForIdleSync();
    sendKeys(KeyEvent.KEYCODE_1);
    sendKeys(KeyEvent.KEYCODE_SPACE,KeyEvent.KEYCODE_0, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_A);
    

※ 注意:sendKeysメソッドがrunOnUiThreadの以内に行っていけません。

ビュークリック

  1. ビューをクリックするために、Soloのメソッドも利用できています。  よく利用できるメソッド:
メソッド 説明
clickOnActionBarHomeButton() ActionBarのHome/Upボタンをクリックするメソッド。
clickOnActionBarItem(int id) パラメーターIDと一致するActionBarItemをクリックするメソッド。
clickOnButton(int index) ボタンをクリックするメソッド。
clickOnButton(String text) 上記と同様に振舞う。
clickOnCheckBox(int index) チェックボクスをクリックするメソッド。
clickOnEditText(int index) エディターテクストをクリックするメソッド。
clickOnImage(int index) インメージをクリックするメソッド。
clickOnImageButton(int index) インメージボタンをクリックするメソッド。
clickOnMenuItem(String text) メニューアイテムをクリックするメソッド。
clickOnMenuItem(String text, boolean subMenu) 上記と同様に振舞う。
clickOnRadioButton(int index) ラジオボタンをクリックするメソッド。
clickOnScreen(float x, float y) スクリーンをクリックするメソッド。
clickOnScreen(float x, float y, int numberOfClicks) スクリーンをクリックするメソッド。
clickOnText(String text) パラメーターtextと一致するビューをクリックするメソッド。
clickOnText(String text, int match) 上記と同様に振舞う。
clickOnText(String text, int match, boolean scroll) 上記と同様に振舞う。
clickOnToggleButton(String text) トグルボタンをクリックするメソッド。
clickOnView(android.view.View view) パラメーターと一致するビューをクリックするメソッド。
clickOnView(android.view.View view, boolean immediately) 上記と同様に振舞う。

下記の例で行11と行14

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
        EditText editTextPasswordContent = (EditText) solo
                .getView(R.id.editTextSettingPasswordDialogName);
        solo.enterText(editTextPasswordContent, "123456");
        assertEquals("123456", editTextPasswordContent.getText().toString());

        EditText editTextPasswordContentConfirm = (EditText) solo
                .getView(R.id.editTextSettingPasswordDialogNameConfirm);
        solo.enterText(editTextPasswordContentConfirm, "123456");
        assertEquals("123456", editTextPasswordContentConfirm.getText()
                .toString());
        //ダイアログをクロスする
        solo.clickOnButton("OK");

        //ダイアログを再開してから入力されていたパースワードを記憶していますが
                //判断テストも行います。
        solo.clickOnView(passwordTextView);
        assertEquals("123456", editTextPasswordContent.getText().toString());
        solo.clickOnButton("キャンセル");
  1. Android自身のperformClickメソッドを利用して値の入力をできること
1
2
3
4
5
6
7
8
9
View view = (View) mActivity.findViewById(R.id.textViewsearch);

mActivity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        view.performClick();
    }
});
mInstrumentation.waitForIdleSync();

フォカスリクエストとクリア

  1. フォカスリクエストでは、Android内のrequestFocusメソッドを利用してフォカスがリクエストできること
1
2
3
4
5
6
7
8
9
View view = (View) mActivity.findViewById(R.id.textViewsearch);

mActivity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        view.requestFocus();
    }
});
mInstrumentation.waitForIdleSync();
  1. フォカスクリアでは、Android内のclearFocusメソッドを利用してフォカスがリクエストできること
1
2
3
4
5
6
7
8
9
View view = (View) mActivity.findViewById(R.id.textViewsearch);

mActivity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        view.clearFocus();
    }
});
mInstrumentation.waitForIdleSync();

ビューチェック

画面上のコントロールを取得してから、Android自身のsetCheckedメソッドを利用して 値の入力をできること

1
2
3
4
5
6
7
8
9
View view = (View) mActivity.findViewById(R.id.textViewsearch);

mActivity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        view.setChecked(isChecked);
    }
});
mInstrumentation.waitForIdleSync();

ActivityのUIスレッド同期化とウエイトについて

下記のハードコピーに、ActivityのUIスレッド間の同期化とウエイトはよく瀕発しますので 常に使える方法として、整理して記述しています。

●スレッドのウエイト

Activityのスタート後ろ、ウエイトしなけれはなりません、さもないとActivityのスタートは成功しない、スレッドの実行することができない。 下記の方法で参照できます

Activityのスタート後ろ、スレッドのウエイトで、データの準備始まる。

1
2
3
4
5
6
7
8
    mInstrumentation = getInstrumentation();
    mActivity = getActivity();

    mInstrumentation.waitForIdleSync();

    new DataPrepare(mActivity);
    new FinderDataPrepare(mActivity);
    mRes = new Res(mActivity);

●スレッドの同期化

前にスレッドを終わるで、それから、後のスレッドの始まるで、すなわちスレッドウの同期です。 下記の方法で参照できます

データの入力した、Activityを展開する。それで、データは同じでない、Activityは同じでない。

同じのActivity、しかし、スレッドは違うです、intentはActivityのパラメーターです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    initButton();

    mActivity.finish();
    setActivity(null);
    mInstrumentation.waitForIdleSync();

    Intent intent = new Intent(getInstrumentation().getContext(),
        PropertyActivityTest.class);

    long id = 1;
    intent.putExtra(C.bundle.DATA_TYPE, true);
    intent.putExtra(C.bundle.DOC_ID, id);

    setActivityIntent(intent);
    mActivity = getActivity();

同じのActivityを終わるで、スレッドウ同期化後、Activityを再始まる

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
View view = (View) mActivity.findViewById(R.id.textViewcheck);

mActivity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
    view.setChecked(isChecked);
    }
});
mInstrumentation.waitForIdleSync();

View view = (View) mActivity.findViewById(R.id.textViewsearch);

mActivity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
    view.performClick();
    }
});
mInstrumentation.waitForIdleSync();