Ubuntu上のUIテストをPythonを書くだけでかんたんに自動化できるのです。
インストールとUnityのテスト
それではまずAutopilotをインストールしましょう。Autopilotの動作にはUbuntu 12.04以上が必要です。12.10以上であれば公式のリポジトリにパッケージが存在しますので、12.10以上を使うことをおすすめします。
最後のunity-autopilotパッケージは、Unityのテストスクリプト集です。そこで実際にこのテストスクリプトを実行して、どんなことができるか確認してみましょう。listコマンドを使うと、実行可能なテストIDの一覧が得られます。例えばUnityのテストスイートの一覧を取得する場合は次のコマンドを実行してください。
同じテストを複数のテストパターン(シナリオ)で実行する場合は、テストIDの前に数字が表示されます。
実際にいくつかのテストを試してみましょう。UIテスト時は、自動的にマウスやキーボードの操作が行われます。不用意な設定変更やデータの消去を避けるためにも、ゲストアカウントでログインしてから実行した方が良いでしょう。ゲストアカウントは右上の歯車アイコンから「ゲストセッション」を選ぶことでログインできます。
ゲストセッションに移行したらrunコマンドに実行したテストIDを指定します。端末を開いて次のコマンドを実行してください。
これは、Dashを開いてカーソルキーでフォーカスを移動し、最終的にアプリLensをEnterキーで表示させるテストです。AutopilotはDBus経由でUnityの状態を監視し、期待通りアプリLensのアイコンにフォーカスがあたること、アプリLensを表示後はアプリLensアイコンのフォーカスが外れる(入力欄にフォーカスが移動する)ことを確認します。
キーボードやマウスの操作をエミュレートできるため、ibus-anthyを使った日本語入力に関係するテストも可能です。次のテストは、DashやHUDから日本語を入力し[2]、その結果が期待通りになっているかを、いくつかのパターンで確認します。
ちなみにunityテストスイートのすべてのテストを実行する場合は、テストスイート名を指定します。ただしかなり時間がかかります。
もっと簡単なサンプル
今度は実際にテストを作ってみましょう。Pythonの知識さえあれば誰でもかんたんに作成できます。ユニットテストに触れた経験があるなら、すぐにでも書き始められるでしょう。
まず、autopilotパッケージですが、Autopilot開発チームのPPAに不具合修正やドキュメントの追加が行われた、より新しいパッケージが存在するので今後はそちらを使用します[3]。
ひな形を作る
Autopilotでは、ある機能に対する一連のテストを「テストケース」、複数のテストケースやテストスイートを一つのカテゴリーとしてまとめたものを「テストスイート」と呼称しています。
そこでファイルの構成としてまずテストスイート名のフォルダーを作り、その中にテストケースごとにPythonのソースコードファイルを作成すると良いでしょう。今回はテストスイート名を「Recipe」、テストケース名を「Sample」とします。
以下のようなフォルダーとファイルを作成してください。
__init__.pyは、Autopilotにこのフォルダーがテストスイート用に作られることを知らせるために作っています。今回は空ファイルのままで問題ありません。
編集すべきファイルはtest_sample.pyのみです。テストケースはAutopilotTestCaseのサブクラスとして実装しますので、test_sample.pyを次のように編集してください。
たったこれだけで「"Hello autopilot"をキーボードで入力する」テストの完成です。先ほどと同じように、テスト一覧を表示させてみましょう。
runコマンドで実行すると[4]、"Hello autopilot"と入力されることがわかります。
setUp()とtearDown()
一つのテストケースに複数のテストメソッド(今回の場合はtest_keyboard())を記述できます。そうすると、テストメソッドごとの初期化処理や終了処理を共通化したいこともあるでしょう。
そんな時に使えるのがsetUp()とtearDown()と呼ばれるテストフィクスチャーです。テストケースのクラスでオーバーライドすることで、テストメソッドごとの初期化(setUp())と終了処理(tearDown())を設定できます[5]。
前節の例では実行した端末上でキーボード入力を行っていました。しかし本来は端末上ではなく、例えばテキストエディター上でキーボード入力のテストを行いたいかもしれません。その場合はテストごとにテキストエディターを起動する必要があります。これは、setUp()を使って次のように書けます。
テストを実行してみると、テキストエディター(gedit)が起動し、「Hello autopilot」と入力されることがわかるでしょう[6]。
マウスの操作
マウス操作用のクラスも存在します。test_sample.pyのSampleTestsクラスにまず次のメソッドを追加してください。
新しく追加したテストを実行すると、geditが開き、最大化され、マウスが左上に移動して閉じるボタンを押すはずです。
keyboard.press_and_relase()はショートカットキーのように複数のキーを同時に押したい場合に使います。"Super+Ctrl+Up"はUnityにおけるウィンドウを最大化するためのショートカットです。mouse.move()でカーソルを左上に移動し、mouse.click()で左ボタンをクリックさせています。最大化した場合、閉じるボタンが左上に来ているために、これによりウィンドウが閉じられるというわけです[7]。
テスト結果の確認
ここまでの作業では「自動化」をしただけであって、「テスト結果の確認」は行っていません。例えばSuperキーでDashを開くかどうかのテストを行う際、Superキーの入力を行ったあとに、「実際にDashが開いたかどうか」を調べる必要があります。
Autopilotでは各GUIツールキットのイントロスペクションを提供することで、UnityやGtk/Qtアプリケーションの「状態」をDBus経由で取得できるようになっています。
また、テスト本体とテスト対象のアプリケーションは非同期的に動作するため、テスト本体から行ったキー入力の結果がすぐにアプリケーションに反映されるわけではありません。このDBusによる状態の取得と非同期処理を隠蔽するために、AutopilotではEventuallyというクラスを用意しています。
例えば、gedit上で入力した文字列を全選択した上でコピーを行い、クリップボードに期待通りのデータが入っているか確認するテストを実装してみましょう。test_sample.pyの冒頭と、SampleTestsクラスに次のコードを追加します。
新しく追加したテストを実行しましょう。画面上で文字(Hello autopilot)が入力されたあとに、選択(Ctrl+a)・コピー(Ctrl+c)されるはずです。最後のassertThat()では、クリップボードから取得したデータ(get_clipboard_contetnts()メソッド戻り値)が、"Hello autopilot"に一致する(Equals())かどうかを確認します。
まとめ
AutopilotでUIテストを書くための必要最低限の知識を紹介しました。これをもとにそれぞれのアプリケーションごとにテストを書き始めるわけですが、実際に書いてみると「Gtk/Qt用のメソッドやサンプルが少ない」「ドキュメントがほとんどない」という壁にあたると思います。
前者については、現在Unity向けがメインであるためかなかなか進んでいない状況で、ひょっとすると13.04がリリースされたあたりでも変わってないかもしれません。後者については少しずつ改善はされています。現在は、Unityのテストスクリプトを参照することが一番の近道でしょう。
UIテストとしての機能もまだ十分ではありませんが、イメージマッチングを使ったUIテストフレームワークであるXpresserをAutopilotからも使えるようにする予定があるなど、13.04に向けてそしてUbuntu Test Automation Harnessの実現に向けてさまざまな計画が進行中です。
まだ機能が複雑でないうちに、UIテストの自動化を試してみてはいかがでしょうか?