friendlyを使ったwindowsアプリテスト自動化
TRANSCRIPT
Friendly を使ったWindows アプリテスト自動
化
ところで、Windows アプリ開発者の皆さん
Windows アプリ開発者の皆さん
テスト自動化してますか?
やってません!
大きくは二種類に分かれる
部品をテスト
アプリをテスト
部品をテスト
いわゆる単体テスト、コンポーネントテスト。
クラス、メソッド、コンポーネントなどプログラムの一部を切り出してテストを実施する。
テスタビリティーが高い設計でないと、実施不可能。
ウチのレガシーコードに単体テスト付けれるもんなら、付けてみろ!
部品をテスト
対応策 → TDDBC へ GO !
コード品質の改善への近道。
でも、レガシーコードにテスト付けるのは限界があるけどね・・・。
難しい話なので、今日はパス。
今日はこっちの話
部品をテスト
アプリをテスト
アプリをテスト統合テスト、システムテスト、受け入れテスト等。
おなじみの普通にアプリ起動して、テスト項目をこなすテスト。
外部仕様を元に作れる。
これを自動化するということは、手動テストの置き換えにつながる!
繰り返し実施できるので、デグレ防止にピッタリ。
アプリをテスト
じゃあ、なんでやらないの?・どうやっていいかわからない。
・ツール高そうだしね。
・キャプチャリプレイツールって良い噂きかないし・・・。
・一回やったけど、作成、メンテコストかかりすぎ。
と、とにかく、難しいんだよ!
なんで難しいの?
作成が難しい
このタイプのテスト自動化は
・他プロセスを操作する・プログラム
の作成である。
作成が難しい
プロダクトプロセス テストプロセス
この二つは別プロセス、つまり別スレッドで動作する。
つまり、マルチスレッドプログラム。これを忘れてはならない!
ここに、不安定さを生じさせる隙がある!
命令
終わったかな?次の命令
あっと、まだやった。タイミング依存で失敗。
作成が難しい
同期制御が難しい。
あ、不安定さは容認しちゃダメよ。
作成が難しい
インターフェイスが限られている
マウス、キーは、プログラムから操作するには相性が悪い。タイミング依存はどうしても避けられない。
UI オートメーションWindowsApi 選択肢として十分あり。 ただ、ちょっと難しい。 操作できないコントロールもある。
作成が難しい
ユニットテストの場合のテスト対象は、プログラム。あくまで上位のプログラムから使わるために存在する。そのため、テスト自動化と相性が良い。
そもそも、 GUI アプリって、基本は人が使うもの。プログラムから操作するには相性が悪い。
対応・・・
作成が難しい
Friendly は「アプリをテスト」するテストプログラム実装用のライブラリです。
テストは VisualStudio で作成でき、MSTest や Nunit で実行できます。
無料です。
でも、なめたらダメです。
一部上場企業様でも、既に導入されています。
まるで、自分のプロセスのプログラムを操作するように簡単に実装できます。
しかも、操作方法は皆さん既に知っているのです。
他プロセス操作の簡易化
実際に使ってみよう!
以下のページに書かれている内容をデモしました。
http://www.codeer.co.jp/AutoTest/friendly-basic-dynamic
・プロセス間の同期制御
・操作用インターフェイス 大量の既知のインターフェイス。 内部メモリも取得可能。 しかも拡張可能。
さっきの問題は全て解決!
もっと贅沢言っていい?
膨大なインターフェイスが使えるようになったのは分かった。でも、多すぎて、どれ使っていいか分かんないのよね。
インテリセンス効かないしさ。
なんとかなんない?
分かりました!
やっぱり、操作するメインは GUI コントロールですよね。
なので、よく使うコントロールに対する操作は、 Friendly の基本機能を使って、実装しておきました!
インストーラとインストールされる機能
Codeer.Friendly Codeer.Friendly.dll Codeer.Friendly.Windows.dll Codeer.Friendly.Windows.Grasp.dll
Codeer.Friendly.Dynamic Codeer.Friendly.Dynamic.dll
Codeer.Friendly.Windows.NativeStandardControls.dll Codeer.Friendly.Windows.NativeStandardControls.dll
Ong.Friendly.FormsStandardControls Ong.Friendly.FormsStandardControls.dll
TestAssistant ツール関連
Friendly の機能を使って実装されてた GUI 操作に特化したライブラリ
Codeer.Friendly.Windows.Grasp.dll
Codeer.Friendly.Windows.NativeStandardControls.dll
Ong.Friendly.FormsStandardControls.dll
Window の取得。
ネイティブウィンドウラッパー
.Net のフォームアプリコントロールラッパ
Friendly の機能を使って実装されてた GUI 操作に特化したライブラリ
Codeer.Friendly.Windows.Grasp.dll WindowControl → Window の取得と汎用操作。
Codeer.Friendly.Windows.NativeStandardControls.dll NativeXXX (NativeButton, NativeEdit, etc) →ネイティブの基本的なコントロールの操作クラス群
Ong.Friendly.FormsStandardControls.dll FormsXXX (FormsButton, FormsTextBpx, etc) → System.Windows.Forms に定義されている 基本的なクラスの操作クラス群
実際に使ってみよう!以下からダウンロードできるサンプルのTestProject/Test1.cs をデモしました。
http://www.codeer.co.jp/AutoTest/test-refactoring-sample
オマケ!テスト作成補助ツール
・画面解析・クラス解析・変数動的参照・メッセージ参照・ GUI 操作によるコード生成・ C# コード簡易実行
実際に使ってみよう!
http://www.codeer.co.jp/AutoTest/testassistant-codegenerate
「操作からのコード生成」機能に関してデモしました。以下のページに使い方が載っています。
実践編
アプリの操作方法はできるようになったものの・・・。
まだ、問題は残っている。
・テストシナリオも可読性を保つ必要がある。
・プロダクトプロセスの変更に追従する必要がある。
・プログラムなのでメンテが必要
保守が難しい
可読性、メンテナンス性を上げる必要がある!
でなければ、費用対効果が悪くて、作った意味がない!
保守が難しい
そのためには、アプリ操作に特化した設計が必要!
保守が難しい
アプリケーションドライバ
←参照元。
保守が難しい
アプリケーションドライバ
プロダクトプロセス テストシナリオ
アプリケーションドライバ
アプリケーションドライバはプロダクトプロセスを操作するためのインターフェイスを提供する。
アプリケーションドライバ
先ほど作ったコードの中には、内部仕様に基づく情報がテストシナリオの中に存在する。
これは、メンテ性が非常に悪い。
例えば、この画面を使うテストシナリオが複数あると、コントロール取得コードが散らばってしまう。
そもそも、内部仕様なので、開発者でなければわからない。
それに、開発側が勝手に変えてしまう場合がある。
なんで必要?
アプリケーションドライバ
・内部仕様に関する情報の隠蔽。
・外部仕様を元に理解でき、 簡単に使えるインターフェイスの提供。
+テスト用の仕様として Fix 。
目的
外部仕様を元に理解できるインターフェイスってなに?
アプリケーションドライバ
・ GUI マップ
・ドメインの言葉にしたメソッド、プロパティー
・ショートカット
以降の内容は、次からダウンロードできるサンプルのTestProject/Test1.cs 、 Test2.cs で参照できます。http://www.codeer.co.jp/AutoTest/test-refactoring-sample
アプリケーションドライバGUI マップ
public class EntryForm { public WindowControl Form { get; private set; } public FormsTextBox TextBoxName { get; private set; } public FormsNumericUpDown NumericUpDownAge { get; private set; } public FormsComboBox ComboBoxSkill { get; private set; } public FormsButton ButtonOK { get; private set; }
public EntryForm(WindowControl entryForm) { // 内部仕様の情報を使ってマッピング ここで隠蔽され、テストシナリオには表れない。 Form = entryForm; dynamic entryFormCore = entryForm.AppVar.Dynamic(); TextBoxName = new FormsTextBox(entryForm.App, entryFormCore._textBoxName); NumericUpDownAge = new FormsNumericUpDown (entryForm.App, entryFormCore._numericUpDownAge); ComboBoxSkill = new FormsComboBox (entryForm.App, entryFormCore._comboBoxSkill); ButtonOK = new FormsButton(entryForm.App, entryFormCore._buttonOK); }}
GUI を外部仕様としてとらえる。GUI を特定する変数名称は内部仕様なので、ここで隠蔽する。
これを公開
注)継続的デリバーを素直に読むと、ウィンドウの種類を外に出すべきではないとも読み取れます。 しかし、 GUI の種別も外部仕様と考えることができるので、私は、プロジェクトによっては、 これも許容範囲と考えています。
アプリケーションドライバドメインの言葉にしたメソッド、プロパティー
public class Main { MainForm _form;
public Main(WindowControl form) { // マッピング処理等・・・ }
public void Entry(string name, int age, EmployeeManagement.Skill skill) { //ボタンクリック Async asyncEntry = new Async(); _form.ButtonEntry.EmulateClick(asyncEntry);
// 次の画面処理 EntryForm entryForm = new EntryForm(_form.Form.WaitForNextModal()); entryForm.TextBoxName.EmulateChangeText(name); entryForm.NumericUpDownAge.EmulateChangeValue(age); entryForm.ComboBoxSkill.EmulateChangeSelect((int)skill); entryForm.ButtonOK.EmulateClick(); } }
GUI情報隠蔽
公開
GUI 操作ではなく、登録というフィーチャをテストしたい。
メリット ・シナリオはさらにシンプルに。 ・ GUI が変わっても、メンテはここだけ。 デメリット ・ GUI の詳細のテストとは合わない。
アプリケーションドライバ
ショートカット目的の状態(画面)まで移動する。目的の画面の操作は詳細に書きたいとして、そこにたどり着くまでの画面の操作は、その関心の対象外。そのため、できたら関数一発で、そこにたどり着きたい。
public Main GetMain(){ //…特定の状態へ遷移する処理}
注)継続的デリバーには、このようなアドバイスはありません。 私の経験から有効な方法なので、ここでまとめて紹介しています。
テストシナリオ
アプリケーションドライバ
アプリを簡単に操作する手段を提供するよ。私の仕事はアプリ操作。内部仕様も知ってるよ。でも、それは秘密だけどね。
ていうか、アプリのことは気にしないで。私のことをアプリだと思って話して。
外部仕様に沿って、テストシナリオを簡潔に記述するよ。私の仕事は品質保証。
難しい内部仕様なんて知りたくもないし。
アプリケーションドライバ
あれ?
アプリケーションドライバ
アプリケーションドライバ
てことは、アプリケーションドライバって開発者が作ればいいんじゃない?
内部仕様知ってるし。アプリケーションドライバが使っている内部仕様は規約として守りやすいしね。
アプリケーションドライバ
テストシナリオ
てことは、テストシナリオは検証チームが書いたらいいじゃないかな?
外部仕様だけで、使えるインターフェイスを提供してくれるんでしょ?
アプリケーションドライバ
そういう仕事分担もありです。
アプリケーションドライバ
まあ、しかし検証チームの本業は検証だし、トラブルが発生したら開発側がサポートしたり、プログラムの分からないところを教えたり、それは当然必要。
チームとして自動化を成功させるという認識が重要。
アプリケーションドライバ
明日からでも導入しよう!
Friendly とテスト自動化!
ご清聴ありがとうございました。