Jeffsuke is not a pen.

🏊‍♂️🚴‍♂️🏃‍♂️💻📱

Objective-CとTDD

このエントリーは、TDD Advent Calendar 2013 の 6日目です。
ある日友人に「iOSアプリを作る人はあまりユニットテストしない」と言われた。自分もあまり書いた事はなかった。よく職場とかで言われるのは、

  • ユニットテストを書く工数>受けられる恩恵
  • iOSアプリはなんとなくでも作れるので、TDDとかいらない。
  • テスト維持するの大変じゃん。

よし、良い機会だ、自分の為にもまとめよう。

TDDとは

そもそも、TDDって何さ。@biacさんが詳しくまとめてくれました。 ユニットテストをベースに開発を進める事だと理解している。ロジックのエラーを捉えたり、デグレードを防げたり、依存関係の少ないコードを書けたりと利点が多い。TDDを行うには依存関係の解決が大事。
これを実現する為に、ユニットテストが使われる。では、ユニットテストとは? 「 最小である1つの機能をテストする事」を指し、小さく、早く、単位ごとにテストができ非常に有用だ。
逆に、ユニットテストにもできないことはあり、その一つにUIテストがある。これはBDDの話になるので、以下の記事を見て欲しい。

iOS 向けTDD/BDDフレームワークやモックフレームワークの現状 - laiso - iPhoneアプリ開発グループ

Objective-Cでのテスト:XCTest

Xcode5でプロジェクトを作成すると、XCTestというテストフレームワークのクラスが自動生成される。また、Xcode5からはBotsと呼ばれるCIも導入された。さらに、Xcode4で使われていたOCUnitからのマイグレーションツールもあり移行も割りとスムーズ。

f:id:jeffsuke:20131215031536j:plain

また、テストナビゲーターから、ワンクリックでテストケースを一つづつ実行可能になった。

テストケースは通常のObjective-Cと同様に書ける。例を以下に示す。

@interface ExampleTests:XCTestCase
@end

@implementation ExampleTests
- (void) testExample {
    XCTAssertTrue(2 + 2 = 4);
}

TDDで依存関係の少ないコードを書く

では、テストケースは分かったが、どうテストを書くのだろうか。以下のメソッドにTDD的な考えを導入しよう。

- (BOOL) saveIDNumberToDB:(NSNumber *)ID {
    JSKDataManager *dataManager = [JSKDataManager sharedInstance];
    [dataManager addID:ID];
    
    return [dataManager save];
}

まず、何かしらのシングルトンのデータマネジャーに、IDのNSNumberを渡し、保存し、その成否をリターンしている。 最小単位でテストするために、依存関係を取り除く必要がある。依存箇所をプロパティにすることを今回は考える。すると、シングルトンこの場合最小単位のテストは、

- (void)testSharedInstanceCreated {
    JSKViewController *viewController = [[JSKViewController alloc] init];
    XCTAssert([viewController.dataManager class] == [JSKDataManager class]);
}

これに合わせてコードを変更すると、

@interface JSKViewController ()
@property (nonatomic, strong) JSKDataManager *dataManager;
@end

@implementation JSKViewController
- (BOOL) saveIDNumberToDB:(NSNumber *)ID {
    self.dataManager = [JSKDataManager sharedInstance];
    [self.dataManager addID:ID];
    
    return [self.dataManager save];
}

という形になり、依存関係の少ないきれいなコードに近づけるというわけだ。さらに、TDDで開発をしていれば、仕様変更時のテストの変更も最小限になるため、かかる工数よりも受けれる恩恵が多そうだ(もちろん出来ないことは出来ないけどね)

まとめ

今回はObjective-CとXcodeにおけるTDDについて調べた。TDDは、デグレードを防ぎ、メソッド感の依存関係を少なく記述するための指針となる。iOSアプリの世界でも、モデルコントローラー間では多くの恩恵を受けれそうだ。