2019/05/05 - UI自動テストが実用に

Weather Typing 3.6を公開するにあたって、UIテストの自動化を研究していた。今、ウェザタイのリグレッションテストの項目が約2500件、WPFだけで500件くらいある。これだけあるとテストだけで数週間かかってしまい、何か修正してもテストがめんどうで公開をあとまわしにしてしまう。人を増やさずになんとかならないか考え続けた結果、UIテストがそろそろ実用的になっていそうなので、やってみた。

Webの世界ではSeleniumがよく使われているが、それをデスクトップアプリやモバイルアプリに使えるようにしたAppiumというフレームワークがある。バイナリだけでテストができるので、C#+Xamarin.Formsで作ったアプリでも、C#でテストコードを書いて、マルチプラットフォームでテストできる。

で、まあいろいろ苦労はしたが、最終的にWPFのテストは77%の自動化ができた。しかも面倒なテストはほとんど自動化できたので、手動のテストを含めても、早ければ1日でテストが終わる感触。

なお、今回はWPFなので、WindowsAppDriverを使用。Windowsストアアプリも同じものが使えるはずで、Android他はまた違うAppiumのドライバを使うが、テストコードは基本的に共有ができるはず。

Palm OSのアプリを作ってた時代は、グレムリンテスト(モンキーテストの自動化)くらいしかなくて、とてもちゃんとUIのテストはできなかった記憶があるけど、RPAも実用的になっている今の時代、以下のような項目くらいは自動化できるようになっていた。

  • ボタンなどをクリックして画面遷移した先のラベルなどが表示されていることを確認する
  • 入力ボックスの文字数制限やエラー表示が正しいことを確認する
  • 複数のインスタンスを起動して、互いに協調動作(具体的にはネット対戦)することを確認する

具体的には、プログラム上でUI部品にIDを与えておくと、実行時にそのIDからテキストを取得したり、クリックしたりできる。さらにテスト自体はプログラミング言語を使って書くので、ロジックは入れ放題。プラットフォーム依存になるけどファイル操作なんかも普通にできるので、かなり自由度が高い。

逆に、どうしても自動化できなかったのは例えば以下の項目。そりゃそうだろうね、っていう感じ。頑張ればできるかも知れないけど手動でやってもたいしたことはない。

  • 文字の色や背景画像を確認する
  • 音がなる、ならないことを確認する
  • 拡大縮小やスプリッターの位置を確認する
  • マウスカーソルの表示・非表示を確認する

UIテストをやる前は、結局目で見ないとおかしいことに気付かないから意味がないかな、と思ってたけど、Appiumの場合、実際にマウスでクリックしたりキーボードを入力したりするので、手動でテストするのとそんなに変わらない。テストスピードがあまり早くないのもあって、テストの様子を見ていればレイアウトが変になっていたりしても割と気付く。

手動ではどうしても確認にミスが出るので、むしろ自動の方が正確だし、手動の時は全組合せのテストは不可能である程度抜粋にせざるをえなかったが、自動なら何も考えずに全組合せテストしてもたいしたことはないので網羅的になる。

メモ。今回のUIテストでは以下のことを気を付けて作ってみた。

  • 汎用的になるようにする。エラーメッセージの確認なんかは、メッセージそのものを確認するとエラーメッセージの変更に堪えられないので、キーワードを含むかどうかだけ確認するようにしてみた。
  • いつでもテストを実行できるようにする。前提条件がないように、テスト項目開始時に設定ファイルやリプレイファイルなんかを全て削除して、必ず同じ条件で実行できるようにしてみた。

ついでに、WindowsAppDriverでハマったこと。

  • Xamarinからだと直接Accessibility IDを設定できない。Xamlから、Effectを使ってIDを設定し、各プラットフォーム固有コードでIDを設定するようにした。
  • 画面に表示されていない項目をクリックしたりはできないので、スクロールがめんどう。結果的にWindows用に最適化されている状態なので、Androidとかでどうしよう。
  • キーボードが101キーボードになっていて、打てない記号がある。特にバックスラッシュを打つ方法が見つからなかった。
  • Windows用のAppium用クラスとAndroid用のAppium用クラスが別物なので、統一的に扱えない。なので、一個ラップしたクラスを作って同じように使えるようにした。
  • Async/Awaitするとテストが終わってしまう。WaiterのUntilをうまく使って回避するくらいしかない。

コメントする