iOS向けの受け入れテストフレームワークはたくさん出揃っているんだけどMacアプリ向けのは全然話聞かないなあ、と思っていたので試してみた。
KIFとは
KIFはiOSアプリ向けの受け入れテストツール。ユーザーから見たアプリの正しい振舞いを検証する。ユーザー操作をエミュレーションするAPIを備えたライブラリを使ってシナリオを記述し、アプリに含めてビルドして実行する。
はじめよう
まずXcodeからテスト対象となるCocoaアプリケーションを作成します。今回は"KIFMac01"という面白気のない名前で作成しました。
仕様としてはウィンドウ中央にあるHelloボタンが押せるというだけのアプリケーションです。
MainWondows.xibを開いてPushボタンのパーツを追加します。そしてダブルクリックしてタイトルをHelloにします。これでアプリケーションは完成です(!)。
ビルド実行してアプリケーションがただしく使えるかを手動でテストしてみてください。
そうしたら次は自動テスト用のビルドの為に下準備をします。
一旦黒い画面を開いてコマンドラインからgit-submodule を利用して取得したMac版KIFのソースをプロジェクトにインポートします。
cd KIFMac01 git init mkdir Vendors git submodule add https://github.com/joshaber/KIF.git Vendors/KIF-Mac
Xcode上で
通常アプリケーションとテスト実行ターゲットを分けるために、元のターゲットを複製します。
作成したターゲットの依存ターゲットにKIFMacを追加、リンクバイナリにKIF.framewrokを追加します。
プリプロセッサマクロに RUN_KIF_TESTS=1 を設定し、共通のAppDelegateからテスト実行に分岐させます。
// AppDelegate.m #import "AppDelegate.h" #ifdef RUN_KIF_TESTS #import "KMTestController.h" #endif @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { #ifdef RUN_KIF_TESTS [[KMTestController sharedInstance] startTestingWithCompletionBlock:^{ exit([[KIFTestController sharedInstance] failureCount]); }]; #endif } @end
KMTestController はわたしたちがこれから作るテストコントローラーです。この中でテストシナリオを追加していきます。
以降はKIFMac01のアプリ本体のターゲットではなく、テスト用に作成したターゲットにソースを追加していきます。
Helloボタンを押すテストと、Goodbyテストを押すテストの2パターンを作ります。
自動テストの成功と失敗、栄光と挫折を体験する為にわざと失敗するテストも入れました。Goodbyボタンはまだ作ってないので押すことができない=失敗するはずです。
// KMTestController.h #import <KIF/KIFMac.h> @interface KMTestController : KIFTestController @end
// KMTestController.m #import "KMTestController.h" #import "KIFTestScenario+Additions.h" @implementation KMTestController - (void)initializeScenarios; { [self addScenario:[KIFTestScenario scenarioToHello]]; [self addScenario:[KIFTestScenario scenarioToGoodBy]]; // GoodByボタンを設置してないので失敗するはず } @end
シナリオの具体的な処理はKIFTestScenarioのObject-Cカテゴリとして自分で作成します。標準で操作のタイムアウト(対象のViewが見付からないとか)が確か30秒ぐらいなので1秒に変更してます。
// KIFTestScenario+Additions.h #import <KIF/KIFMac.h> @interface KIFTestScenario (Additions) + (id)scenarioToHello; + (id)scenarioToGoodBy; @end
// KIFTestScenario+Additions.m #import "KIFTestScenario+Additions.h" #import <KIF/KIFMac.h> @implementation KIFTestScenario (Additions) + (id)scenarioToHello; { KIFTestScenario *scenario = [KIFTestScenario scenarioWithDescription:@"Test that user can click 'Hello' button."]; KIFTestStep* step = [KIFTestStep stepToClickViewWithTitle:@"Hello"]; step.timeout = 1.0; [scenario addStep:step]; return scenario; } + (id)scenarioToGoodBy { KIFTestScenario *scenario = [KIFTestScenario scenarioWithDescription:@"Test that user can click 'GoodBy' buton."]; KIFTestStep* step = [KIFTestStep stepToClickViewWithTitle:@"GoodBy"]; step.timeout = 1.0; [scenario addStep:step]; return scenario; } @end
テストの手筈が整いました。ではテストターゲットを実行してみましょう。
以下のようにコンソールに結果が出力され、アプリケーションは自動で終了します。
2012-10-13 22:00:28.431 KIFMac01IntegeRationTests[9208:303] Logging KIF test activity to /Users/laiso/Library/Logs/KIF Tests Oct 13, 2012 10.00.28 PM GMT+09.00.log 2012-10-13 22:00:28.431 KIFMac01IntegeRationTests[9208:303] BEGIN KIF TEST RUN: 2 scenarios 2012-10-13 22:00:28.432 KIFMac01IntegeRationTests[9208:303] 2012-10-13 22:00:28.433 KIFMac01IntegeRationTests[9208:303] --------------------------------------------------- 2012-10-13 22:00:28.433 KIFMac01IntegeRationTests[9208:303] BEGIN SCENARIO 1/2 (1 steps) 2012-10-13 22:00:28.434 KIFMac01IntegeRationTests[9208:303] Test that user can click 'Hello' button. 2012-10-13 22:00:28.435 KIFMac01IntegeRationTests[9208:303] --------------------------------------------------- 2012-10-13 22:00:29.052 KIFMac01IntegeRationTests[9208:303] PASS (0.62s): Click view with title "Hello" 2012-10-13 22:00:29.052 KIFMac01IntegeRationTests[9208:303] --------------------------------------------------- 2012-10-13 22:00:29.053 KIFMac01IntegeRationTests[9208:303] END OF SCENARIO (duration 0.62s) 2012-10-13 22:00:29.053 KIFMac01IntegeRationTests[9208:303] --------------------------------------------------- 2012-10-13 22:00:29.054 KIFMac01IntegeRationTests[9208:303] 2012-10-13 22:00:29.054 KIFMac01IntegeRationTests[9208:303] --------------------------------------------------- 2012-10-13 22:00:29.055 KIFMac01IntegeRationTests[9208:303] BEGIN SCENARIO 2/2 (1 steps) 2012-10-13 22:00:29.055 KIFMac01IntegeRationTests[9208:303] Test that user can click 'GoodBy' buton. 2012-10-13 22:00:29.056 KIFMac01IntegeRationTests[9208:303] --------------------------------------------------- 2012-10-13 22:00:30.067 KIFMac01IntegeRationTests[9208:303] FAIL (1.01s): Click view with title "GoodBy" 2012-10-13 22:00:30.067 KIFMac01IntegeRationTests[9208:303] FAILING ERROR: Error Domain=KIFTest Code=0 "The step timed out after 1.00 seconds." UserInfo=0x100199920 {NSLocalizedDescription=The step timed out after 1.00 seconds., NSUnderlyingError=0x100119c80 "Failed to find accessibility element with the title "GoodBy""} 2012-10-13 22:00:30.068 KIFMac01IntegeRationTests[9208:303] --------------------------------------------------- 2012-10-13 22:00:30.068 KIFMac01IntegeRationTests[9208:303] END OF SCENARIO (duration 1.01s) 2012-10-13 22:00:30.068 KIFMac01IntegeRationTests[9208:303] --------------------------------------------------- 2012-10-13 22:00:30.069 KIFMac01IntegeRationTests[9208:303] 2012-10-13 22:00:30.069 KIFMac01IntegeRationTests[9208:303] --------------------------------------------------- 2012-10-13 22:00:30.069 KIFMac01IntegeRationTests[9208:303] KIF TEST RUN FINISHED: 1 failures (duration 1.64s) 2012-10-13 22:00:30.070 KIFMac01IntegeRationTests[9208:303] --------------------------------------------------- 2012-10-13 22:00:30.070 KIFMac01IntegeRationTests[9208:303] *** KIF TESTING FINISHED: 1 failures
Helloボタンのクリックテストは成功し、Goodbyボタンの方はタイムアウトが発生し失敗したことがわかります。
例によってGithubにこのチュートリアルのソースコードを上げておいたのでうまくいかない時などにチェックアウトして参考にしてください。