連載
» 2014年11月05日 18時00分 UPDATE

スマホ向け無料システムテスト自動化ツール(3):Androidテストで便利なuiautomatorviewer、UiScrollableの使い方、テキスト入力API制限事項の回避方法 (4/4)

[外山純生,テスト自動化研究会(STAR)/Androidテスト部]
前のページへ 1|2|3|4       

テキスト入力APIの制限事項を回避する

 uiautomatorのテキスト入力API「UiObject.setText()」は、テストを実行する端末の言語設定が英語で、かつ、IMEが英語入力モードでないと、想定とは異なる文字列が設定されてしまうことがあります。ここでは、その回避方法を紹介します。

テキスト入力フィールドに非ASCII文字を入力する

 UiObject.setText()は、仮想的なキーボード(PCで一般的に使われるQWERTYキーボード)をタイプし、対応するキーイベントを端末に送信することで、文字の入力を実現しています。

 そのため、QWERTYキーボードでタイプできる文字しか、setText()を使って入力できず、日本語をはじめとする非ASCII文字を引数に指定しても、何も入力できません。

非ASCII文字の入力を可能にするUiautomator Unicode Input Helper

 テキスト入力フィールドに非ASCII文字を入力できるようにするためには、筆者が作成した「Uiautomator Unicode Input Helper」(以降では「UUIH」と書きます)が利用できます。

 UUIHはApache License, Version 2.0のライセンスで提供されており、以下のURLからダウンロードできます。

 UUIHは2つのモジュールで構成されています。

  • Utf7Ime:テストを実行する端末にインストールする特別なIME。テスト実行時にデフォルトのIMEに設定して利用する。このIMEを使うことで、QWERTYキーボードでタイプできる文字の組み合わせから、任意のUnicode文字を入力できる
  • ヘルパーライブラリ:日本語などのUnicode文字列を、Utf7Imeが解釈できるASCII文字列に変換するためのライブラリ。uiautomatorのテストスクリプトへソースコードをコピーして利用する

 それぞれのモジュールのインストール方法と準備については、UUIHの「README.ja.md」の「準備」の節を参照してください。なお、サンプルのテストスクリプトには、すでにヘルパーライブラリを組み込んであります。

 サンプルを動かしたい場合は、Utf7Imeだけをテストを実行する端末にインストールし、デフォルトのIMEに設定してください。

テストスクリプトの修正

 次に、テストスクリプト側で、UiObject.setText()で入力しようとしている文字列について、それぞれ以下のような修正を行います。

UiObject editText = ...; // テキスト入力フィールドを指すUiObject
editText.setText("日本語");
修正前
UiObject editText = ...; // テキスト入力フィールドを指すUiObject
String encodedText = Utf7ImeHelper.e("日本語")
editText.setText(encodedText);
修正後

 上記のように、直接setText()に入力文字列を指定する代わりに、ヘルパーライブラリが提供するUtf7ImeHelper.e()メソッドを使って変換した文字列を指定するようにします。Utf7ImeHelperクラスはjp.jun_nama.test.utf7ime.helperパッケージにあります。

 なお、&以外のASCII図形文字しか入力しない箇所については、上記修正は必要ありません(修正しても問題ありません)。

端末の言語設定が英語以外でも動作するようにする

 UiObject.setText()は、テキスト入力フィールドが空でない場合に備えて、内部的にUiObject.clearTextField()を呼び出し、テキスト入力フィールドをクリアしてから、引数に指定された文字列を入力するようになっています。

 ところが、端末の言語設定が英語以外になっていると、テキストフィールド入力フィールドのクリア処理が正しく動作しません。

 例えば、端末の言語設定を日本語にすると、最初に紹介したCustomerModifyTest1クラスのテストも、顧客氏名を修正する箇所で失敗してしまいます。具体的には「John Doe 2」を「John Smith」に修正しようとすると、「John Smith Doe 2」となってしまいます。

 uiautomatorは、テキスト入力フィールドをクリアするときに、以下の操作を行っています。

  1. テキスト入力フィールド内の左端の近くをロングタップ
  2. アクションバーの[Select all]メニュー(下図の赤丸で囲んだ部分)をタップし、「全て選択」状態にする
  3. DELETEキーを押し、全ての文字をクリア
03_uiautomator_16.png 英語版の[全て選択]メニュー

 端末の言語設定を日本語にすると[Select all]メニューの名前(contentDescription属性)が[全て選択]に変化してしまうため、テキストを全て選択した状態にできず、最初の単語だけがクリアされてしまうのです。

03_uiautomator_17.png 日本語版の[全て選択]メニュー

 この問題を解決するために、アクションバーのメニュー選択部分のロジックだけを修正した、以下のようなi18nClearTextField()メソッドを用意します。

/**
 * 引数に指定されたテキスト入力フィールドについて、すでに入力されている文字列をクリアする。
 * テストを実行する端末の言語設定が英語以外でも動作する。
 * 
 * @param editText 内容をクリアしたいテキスト入力フィールド
 */
public static void i18nClearTextField(UiObject editText) throws UiObjectNotFoundException {
    editText.longClickTopLeft();
    // "Select all"のリソース文字列を android.R.string.selectAll から取得する。
    // この方法で、端末の言語設定に応じた文字列を取得できる。
    String selectAllDesc = Resources.getSystem().getString(android.R.string.selectAll);
    UiObject selectAll = new UiObject(new UiSelector().descriptionContains(selectAllDesc));
    if (selectAll.waitForExists(50))
        selectAll.click();
    SystemClock.sleep(250);
    UiDevice.getInstance().pressDelete();
}

 UiObject.clearText()の代わりに、こちらを呼び出すことで、端末の言語設定が英語以外でも意図通りに動作するようになります。すでに文字列が設定されているテキスト入力フィールドに対してUiObject.setText()したい場合は、その直前に上記メソッドを呼び出してください。

サンプルのテストスクリプトについて

 サンプルのテストスクリプトでは、CustomerModifyTest3クラスに、この二つの問題に対応したテストを用意してありますので、参考にしてください。デフォルトのIMEをUtf7Imeにし、端末の言語設定を日本語にしてお試しください。

 対応の要となるクラスは、DetailPageUnicodeSupportクラスです。このクラスはDetailPageクラスを継承し、「氏名」欄へ入力するtypeName()メソッドを、日本語対応版になるようにオーバーライドしています。

package com.nowsprinting.hellotesting.uiautomator.page;
 
import com.android.uiautomator.core.UiObjectNotFoundException;
import com.nowsprinting.hellotesting.uiautomator.util.CommonUiActions;
 
import jp.jun_nama.test.utf7ime.helper.Utf7ImeHelper;
 
/**
 * Detail画面を表すクラス(氏名欄のみUnicode文字の入力に対応)。
 */
public class DetailPageUnicodeSupport extends DetailPage {
 
    @Override
    public DetailPage typeName(String name) throws UiObjectNotFoundException {
 
        if (name != null) {
            // 国際化対応版のclearTextField()を最初に呼び出す
            CommonUiActions.i18nClearTextField(mNameTextField);
            // Utf7Imeが理解できる文字列に変換してからsetTextする
            mNameTextField.setText(Utf7ImeHelper.e(name));
        }
        return this;
    }
}

次回は、BDDの主要ツールの一つ「Calabash」について

 2回にわたって、uiautomatorを紹介しましたが、いかがでしたでしょうか。uiautomatorは、他者が作成したアプリを操作できるという点では非常に強力なツールです。まだ開発途上の部分もありますが、今回紹介したノウハウを活用すれば、連載第1回で紹介した「システムレベルの機能テスト」で必要となる項目の多くを自動化できるはずです。

 今回の記事では紹介しきれませんでしたが、アプリの強制終了時など、不意に発生する事象に対しても対応できる「UiWatcher」という仕組みも用意されています。筆者のブログに、使い方を紹介していますので、興味のある方は調べてみてください。

 次回はBDD(Behavior-Driven Development/振る舞い駆動開発)の主要ツールの一つである「Calabash」を紹介します。

著者プロフィール

外山 純生

テスト自動化研究会(STAR)Androidテスト部

NTTソフトウェア株式会社勤務。数年前よりAndroidアプリケーション開発にかかわり始めたのを切っ掛けに、Androidにおける自動テストに興味を持つようになる。Android関連プロジェクトに対する技術支援業務に携りながら、Android向けのテストツールがもっと広く使われるようになることを願って、ブログにて技術情報を発信中

Blog:sumioの技術メモ

Twitter:@sumio_tym


前のページへ 1|2|3|4       

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。