Flutterアプリを自動テストしたい話
こんにちは、エンジニアの斉藤です。
今回はAppiumでFlutterアプリを自動テストしたいという話です。
以前、弊社藤原のAppiumに関する記事を読んで私もAppiumを試してみたところ、自動でアプリが操作できる機能にとても感心しました。
私はFlutterアプリ開発に関わることがあったので、「FlutterアプリもAppiumで動くのか?」と興味を持ち、調査を始めました。
本記事ではその調査においてどのような課題・対応があったかを紹介します。
本記事内の登場要素
この記事では、要素やツールが登場するため、それぞれの役割を記載しておきます。
- Appium
- モバイルアプリの自動テストツール。UI操作を自動化することで、テストや一定の操作を効率化できます。
- https://appium.io/docs/en/latest/
- Appium Inspector
- Appiumで自動テストを作成する際に、画面要素を特定・調査するツールです。
- https://github.com/appium/appium-inspector
- Driver
- Appiumが端末を操作するための仕組み。OSごと(Android、iOS)や特定の環境(Flutter用)に応じたdriverが存在するようです。
- https://appium.io/docs/en/2.16/intro/drivers/
- Flutter
- Googleが提供するクロスプラットフォームフレームワーク。Android, iOSの両方のアプリを一つのコードベースで構築することができます。
- https://flutter.dev/
- Semantics
- Flutterの要素にIDを付与するWidget。自動テストで要素を特定する際に使用します。
- https://api.flutter.dev/flutter/widgets/Semantics-class.html
1. Flutter用のDriverではなく、OSごとのDriverを使う
Appiumを動かす際には、Driverという概念がでてきます。
このDriverは対象の端末を動かすための仕組み、と呼べるもので、例えばAndroid, iOSというOSの違いでも異なるようです。
Flutterというクロスプラットフォーム環境なので、Flutter用のDriverがあれば、OS間の違いを吸収でき、ワンソースでテストが書けることを期待していました。
調査したところ、以下のようなDriverが見つかりました。
これらのDriverを試してみると、テスト用のスクリプトは書けるものの、Appium Inspectorが動作しないことがわかりました。
Appium Inspectorが使えないと、要素の調査がしづらく、自動テスト開発の効率が下がります。そのため、これらのDriverの使用を断念しました。
改めてDriverの説明を読んでみると、Flluterバージョン3.19からOSごとのDriverでもFlutterアプリが動作することがわかりました。
結論として、OSごとのDriverを使用することで、Appium Inspectorによる要素調査もしやすく、開発環境に適していると判断しました。
以下、FlutterサンプルアプリをAppium Inspectorで要素調査している時のスクリーンショットです。
2. Androidで要素を選択するには画面に表示させる必要がある
Flutterの仕組み上、iOSでは画面の外にあるページ内要素も取得できるようで、画面外の要素を押すスクリプトでは自動的にスクロールして押すことができました。
しかし、Androidはそれができず、画面に見えている範囲でしか要素を取得できないようです。
苦肉の策として、Androidでは自動的にスクロールして要素を探すという手法を取りました。
(その他にもAndroidでは、ソフトウェアキーボードに隠された要素は、存在しないと判定されてしまうようです。)
3. ラベルのない要素にSemanticsを設定する
自動テスト調査は、ラベル(= 要素内のテキスト)指定して、要素を選択するような方法で進めていました。
しかし、アイコンそのものがボタンである要素など、ラベルがない要素は選択できないことに気づきました。
そこで、調べてみるとSemanticsという方式がFlutterには用意されていることがわかりました。
これを利用すると、その要素にいわゆるidを振ることができ、Appiumはそのidで要素を特定できるようです。
「自動テストのためにアプリ側に手を入れる」ことになりますが、アプリ自体のUIや動作に影響しないので、この作業に抵抗はありませんでした。
以下、該当の要素にSemanticsを設定した場合と、していない場合の実装抜粋です。
// Semanticsを設定した場合
...
floatingActionButton: Semantics(
label: "floating-button-test-id",
child: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
)
...
// Semanticsを設定していない場合
...
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
)
...
まとめ
FlutterアプリでAppiumを動かした時の課題とその対策を紹介しました。
手間のかかるポイントはありますが、自動でUI操作を行えることで、自動テスト環境を構築する可能性が見えました。
またアプリの保守をしていると、テストだけではなく、ある一定の動作を何度も行う、ということがあるのでそういった作業を自動化できる、という点でも魅力を感じました。
補足:自動テストツールの選択肢
この記事を書いている時点では、MagicPod などのように、WEBサービスとして自動テスト実施を謳っているものもあるようです。
もしかしたら、今後は本記事で遭遇したような苦労をしなくても、WEBサービスが解決してくれる未来もあるかもしれませんね。(そうなってくれると、予算さえあればなんとかできるので嬉しいと考えています)
それではまた。