カッターの下で、ユニットおよび機能テスト用のツールを検討し、簡単な例を示します。
テストアプリケーション
例として、簡単な計算機を書くことにしました。 このアプリケーションには実用性がなく、機能が非常に劣っていますが、私の意見ではテストの作成を開始するだけで十分です。
便宜上、完成したアプリケーションをgithubに投稿しました 。
単体テスト
単体テストを作成するために、すばらしいツール-Cedarを使用します。
RSpecスタイルでテストを記述できるため、コードの構造と読みやすさが向上します。
githubはフレームワークの構築方法のかなり完全な説明を提供しましたが、いくつかのマシンで組み立てるという質問が発生したとき、このすべてのルーチンを実行する単純なスクリプトがbashで書かれました。
インストールするには、プロジェクトのクローンを作成し、install.shスクリプトを実行する必要があります。Cedarは/ opt / cedarにインストールされ、シンボリックリンクがユーザーのホームディレクトリに追加されます(プロジェクトへの接続時に便利です)。
Cedarを組み立てた後、テストターゲットを構成する必要があります。
- プロジェクトに新しいターゲット(空のアプリケーション)を追加し、UnitTestsという名前を付けました。
- Cedarをターゲットにリンク(バイナリをライブラリにリンク)
- 他のリンカーフラグに追加-ObjC -all_load -lstdc ++
- AppDelegateを削除します。 これは必要ではないかもしれませんが、必要ではありません。
- 次のようにmain.mを編集します
int main(int argc, char *argv[]) { @autoreleasepool{ return UIApplicationMain(argc, argv, nil, @"CedarApplicationDelegate"); } }
最初のテストを書きましょう。
UnitTestsターゲットに次の内容のFooBar.mmファイルを作成します。
#import <Cedar-iOS/SpecHelper.h> using namespace Cedar::Matchers; SPEC_BEGIN(FooSpec) beforeEach(^{ NSLog(@"before each"); }); afterEach(^{ NSLog(@"after each"); }); describe(@"Foo", ^{ it(@"YES should be YES", ^{ YES should equal(YES); }); }); SPEC_END
これで、テストのターゲットを起動できます。すべてが正しく構成されていれば、シミュレーターは、テストが記述されるセル内のテーブルから開始します。
計算機に戻ります。 計算を行うある種のシングルトンクラスがあるとします。CalculationManagerと呼びましょう。 このクラスのインスタンスを返すメソッドが必要です。sharedInstanceと呼びましょう。
この場合のテストを書きましょう。
メインターゲットに空のCalculationManagerクラスを作成し、次の内容のテスト用の別のファイル(CalculationManager.mmなど)を追加します。
// CalculationManagerSpecs.mm #import <Cedar-iOS/SpecHelper.h> using namespace Cedar::Matchers; #import "CalculationManager.h" SPEC_BEGIN(CalculationManagerSpecs) describe(@"CalculationManager", ^{ it(@"sharedInstance should not return nil", ^{ id instance = [CalculationManager sharedInstance]; instance should_not be_nil; }); }); SPEC_END
開始すると、テストが失敗することがわかります。
テストが正常に実行されて続行されるように、実装を追加します。
加算および減算演算のテストをいくつか追加します。
describe(@"calculations should be correct", ^{ CalculationManager *manager = [CalculationManager sharedInstance]; it(@"addition should be correct", ^{ NSInteger left = 5; NSInteger right = 37; NSInteger etalonResult = 42; NSInteger realResult = [manager add:left with:right]; realResult should equal(etalonResult); }); it(@"subtract should be correct", ^{ NSInteger left = 14; NSInteger right = 12; NSInteger etalonResult = 2; NSInteger realResult = [manager subtract:right from:left]; realResult should equal(etalonResult); }); });
それだけです。アプリケーションは単体テストで十分にカバーされていると考え、インターフェイスのテストに進みます。
インターフェイステスト
iOSアプリケーションインターフェイスをテストするためのツールは多数ありますが、私が自分で使用しているツール、つまりCalabash-iOSとFrankについてお話したいと思います。
これらのツールは非常に似ており、どちらもCucumberでテストを記述でき、Rubyで実装されます。唯一の違いは機能にあります。
フランクから移行しなければならなかったプロジェクトの1つで、私はCalabashを使用してテストを実行しましたが、それらはすべてすぐに実行されました。少し変更するだけで済みました。
今、私はカラバッシュに落ち着きました。 多くのiOS開発者はCucumberに精通していないと思います。そのため、Cucumberの仕組みとテストの書き方について少しお話したいと思います。
きゅうり
決してこの説明に忠実であるふりをするのではなく、その作業を理解する方法を説明するだけで、この説明が明確になり、まだ使用することを決めていない人のスタートに役立つことを願っています。
したがって、Cucumberにはいくつかの主要な「エンティティ」があります。
機能は、論理的に関連する(またはプログラマーが決定するように無関係な)いくつかのスクリプトのセットです。 これは、タイトルと簡潔で有益な説明で構成されています。 例:
Feature: Manage Orders As a User I should be able to manage Orders through iOS application
シナリオは、いくつかのユースケースを説明する具体的なシナリオです。 名前と一連のステップで構成されます。
Scenario: Create Order #steps
ステップ-特定のユーザーアクションの説明(ボタン/リンクのクリック、テキストの入力、スワイプなど)。
When I fill in "Title" with "FuuBar" And I touch "Save" button Then I should see alert view titled "Saved successully"
ステップ定義-特定のユーザーアクションの実装。 次のようになります。
When /^I touch "([^"]*)" button$/ do |button_text| touch("button marked:#{button_text}") end
テストを実行すると、Cucumberは1つのステップを実行し、目的の正規表現の実装を検索し、この実装を実行して、次のステップを実行します。 これがそうかどうかはわかりませんが、その本質が明確であることを願っています。
Calabashをプロジェクトに追加しましょう。
プロジェクトディレクトリに移動し、次のコマンドを実行します。
[sudo] gem install calabash-cucumber calabash-ios setup calabash-ios gen
Calabashは別のターゲットをプロジェクトに追加しました。デフォルトでは、project_name-calテンプレートが含まれています。 この目的のためにビルドを完了する必要があります。
これで、テストを実行する準備がほぼ整いました。
生成後、テストの実行方法に関するプロンプトが表示されます
DEVICE=iphone OS=ios5 cucumber
しかし、このコマンドを実行すると、すべてが落ちます。 calabashは、アプリケーションの場所を知りません。 これを行うには、別の変数-APP_BUNDLE_PATHを指定する必要があります。 デフォルトでは、Xcode 4.xはアプリケーションを次の場所に保存します
~/Library/Application\ Support/iPhone\ Simulator/xx/Applications/hash/app_name.app
ここで、xxはiOSバージョン、hashはXcodeによってアプリケーション用に生成された一意のキーです。
.appを見つけて、以下を実行してください。
APP_BUNDLE_PATH='~/Library/Application\ Support/iPhone\ Simulator/xx/Applications/hash/your_app-cal.app' DEVICE=iphone OS=ios5 cucumber
これですべてがうまくいくはずです。
ガード
この方法はあまり便利ではありませんが、まったく正当です。 ひょうたんは、アプリケーションがどこにあるかを知ることができません。 そして、ガードは私たちの助けになります。
Guardは、ファイルシステムを監視し、監視するファイルを変更するときに操作を実行するgemです。 ガードのリストは非常に広範囲ですが、 guard-calabash-iosが必要です。
インストールして使用するには、次の手順を実行する必要があります。
gem install guard-calabash-ios guard init calabash-ios
これにより、ガードファイルが作成されます。これは、ガードに必要なプロパティと監視する必要があるファイルを記述するファイルです。 ( 詳細設定はgithubで見つけることができます。 )
最終タッチ-Xcode設定を開き、派生データを相対として設定します。 これで、Xcodeはアセンブリをプロジェクトディレクトリに保存します。これにより、guard-calabash-iosのスクリプトが必要なAPP_BUNDLE_PATHを自動的に見つけることができます。
ここで、テストを実行するには、プロジェクトフォルダーで以下を実行する必要があります。
guard
テストを書く
すべてがより便利に機能するようになったので、UIテストの作成を開始できます。
Calabashは、スクリプトと実装手順を含む機能フォルダーを作成しました。
計算機でユーザーが2つの数値を加算または減算し、アラートビューに正しい結果を表示できることを確認しましょう。
my_first.featureファイルを編集します
Feature: Add numbers As a User I should be able to perform calculations Scenario: Add numbers When I fill in "left" with "15" And I fill in "right" with "10" And I touch "add" Then I should see "25"
それでもガードが実行されている場合、ファイルを保存すると、テストが自動的に実行され、変更されたファイルのみがテストされます。 次のような機能を持つ複数のファイルがある場合、これは非常に便利です。 各行の後、すべてのテストが実行されるまで待つ必要はありません。
したがって、すべてのテストが失敗しました。これは論理的です。
UIを追加しましょう。
ひょうたんからコントロールにアクセスするには、それらにアクセシビリティラベルを設定する必要があります。 さらに、ボタンにはそれらの碑文からアクセスでき、テキストフィールドにはプレースホルダーからアクセスできます。
プリミティブインターフェイスを作成しました。2つのテキストフィールドと、ナビゲーションバーの2つのボタン「+」と「-」です。
画面にコントロールを追加したら、次のアクションを実行する必要があります。
1.ボタンとテキストフィールドのアウトレットを追加します
2.プレースホルダーをテキストフィールド「左」と「右」に割り当てます
3.ボタンのアクセシビリティラベルを設定する
self.addButton.accessibilityLabel = @"add"; self.subtractButton.accessibilityLabel = @"subtract";
4.ボタンのハンドラーをハングさせる
- (IBAction)addButtonTapped:(id)sender { CalculationManager *calculationManager = [CalculationManager sharedInstance]; NSInteger left = [self.leftTextField.text integerValue]; NSInteger right = [self.rightTextField.text integerValue]; [self showResult:[calculationManager add:left with:right]]; } - (IBAction)subtractButtonTapped:(id)sender { CalculationManager *calculationManager = [CalculationManager sharedInstance]; NSInteger left = [self.leftTextField.text integerValue]; NSInteger right = [self.rightTextField.text integerValue]; [self showResult:[calculationManager subtract:right from:left]]; }
5.結果を表示するメソッドを追加します
- (void)showResult:(NSInteger)result { NSString *resultString = [NSString stringWithFormat:@"%d", result]; [[[[UIAlertView alloc] initWithTitle:@"Result" message:resultString delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease] show]; }
6.ガードが実行されているターミナルに移動してEnterキーを押すと、すべてのスクリプトが実行されます。スクリプトが1つあり、すべてを正しく実行すればテストは成功します。
次に、減算のテストを作成します。
Scenario: Subtract numbers When I subtract 15 from 38 Then I should see "23" as result
開始後、Cucumberはそのような手順を認識していないことを報告し、それらの実装を提案します。
ファイルcalabash_steps.rb(project_dir / features / steps_definitions /)に印刷されているものをコピーして、わずかに編集します。
When /^I subtract (\d+) from (\d+)$/ do |subtrahend, minuend| step %{I fill in "left" with "#{minuend.to_s}"} step %{I fill in "right" with "#{subtrahend.to_s}"} step %{I touch "subtract"} end Then /^I should see "(.*?)" as result$/ do |result| res = query("view:'UIAlertView'", "message").first res.should == result end
実際には、おそらく最初のシナリオと同じメソッドを使用しますが、ここでは、ステップ定義の外観、ステップの実装から他のステップを呼び出す方法(step%{})、値を取得する方法(クエリ)を示したいと思います。およびassertの書き方(すべきです)。
テストはこれで終わりです。
おわりに
説明したテストとアプリケーションは完全にばかげているように見えますが、私の目標は、TDD / BDDをすぐに使い始めることができるこの例の主な機能を説明することでした。
論理的な結論として、次のリンクを引用します。