2012/03/24

OCMockでテストを簡単に書く方法について

OCMockはXcode標準のテスト環境でも利用可能なモックライブラリです。 OCMockを利用すると他のクラス実装に依存しないようなテストを簡単に書くことができるようになります。

そこで、本記事ではOCMockを導入して、プロジェクトに必要な設定を行う方法とOCMockの簡単な利用法について紹介します。なお、利用環境はOS X 10.6.8, Xcode 4.2, OCMock 2.0.1です。

OCMockの簡単な利用法

まずはOCMockの簡単な利用法について少しだけ紹介します。 概要についてはFeatures - OCMockがより詳しいです。

stub

テストで未実装なクラスや外部サーバに依存するようなクラスを利用しなければならず、 とりあえずそれっぽい値を返すようにさせたいときに、stubが使えます。

id mock = [OCMockObject mockForClass:[SampleClass class]];
[[[mock stub] andReturn:@"foobar"] someMethod:@"FOOBAR"];

これで、+someMethod:に引数@"FOOBAR"を指定したときに@"foobar"を返すようなSampleClassのモックが利用可能になります。

STAssertEqualObjects(@"foobar", [mock someMethod:@"FOOBAR"], @"tolower");

この呼び出しは複数登録することができます。

[[[mock stub] andReturn:@"hoge"] someMethod:@"HOGE"];
STAssertEqualObjects(@"hoge", [mock someMethod:@"HOGE"], @"tolower");

ただし、未登録の引数で呼び出すとunexpected method invokedとなります。

STAssertEqualObjects(@"fuga", [mock someMethod:@"FUGA"], @"tolower");  // unexpected method invoked: someMethod:@"FUGA" 

引数が何でもいいという場合にはOCMArgの+anyが利用できます。

[[[mock stub] andReturn:@"*ANY*"] someMethod:[OCMArg any]];

mock

mockを用いると、「これをしたら、あれが呼ばれるはず」というのがテストできます。

次の例はOCMockのソース内のiOS5ExampleTestsにあるコードで、「UITableViewCellEditingStyleDeleteを指定して -tableView:commitEditingStyle:forRowAtIndexPath:を呼んだら -deleteRowsAtIndexPaths:withRowAnimation:が呼ばれるはず」というのをテストしています。

  - (void)testMasterViewControllerDeletesItemsFromTableView {
      MasterViewController *controller = [[MasterViewController alloc] init];
      NSIndexPath *dummyIndexPath = [NSIndexPath indexPathWithIndex:3];
      id tableViewMock = [OCMockObject mockForClass:[UITableView class]];
      [[tableViewMock expect] deleteRowsAtIndexPaths:[NSArray arrayWithObject:dummyIndexPath]
                                    withRowAnimation:UITableViewRowAnimationFade];

      [controller tableView:tableViewMock
         commitEditingStyle:UITableViewCellEditingStyleDelete
          forRowAtIndexPath:dummyIndexPath];

      [tableViewMock verify];
  }

これら以外にもプロトコルのためのモック (mockForProtocol) や、 既存インスタンスの部分的振る舞いを変更できるモック (partialMockForObject) などが利用できます。

なお、テスト結果はLog Nagigator (XcodeでCmd + 7) で見ることができます。

導入とプロジェクト設定

iOS 5 - OCMockを参考にプロジェクトSampleにOCMockを導入します。

  1. Download - OCMockからOCMock 2.0のdmgをダウンロード

  2. dmgをマウントして、次のようにしてライブラリをコピー

    cp -r /Volumes/OCMock\ 2.0.1/iOS ~/src/ocmock-ios
    
  3. ターゲットSampleTestのLink Binary with LibrariesにlibOCMock.aを追加

  4. Header Search Pathに$HOME/src/ocmock-iosを追加

  5. Other Linker Flagsに-force_loadと$HOME/src/ocmock-ios/libOCMock.aと-ObjCを追加

  6. -force_loadの引数が$HOME/src/ocmock-ios/libOCMock.aになっているので順番に気をつけること

なお、Other Linker Flagsでの指定の話題は次の項目を参照してください。 簡単に言うと既存クラスへの追加カテゴリを含む静的ライブラリをリンクすると実行時例外 “selector not recognized” が発生するので、その回避のための手段です。

まとめ

OCMockを導入してプロジェクト設定を行う方法とOCMockの簡単な利用法について紹介しました。

関連情報

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。