web-dev-qa-db-ja.com

iOS-KVO /デリゲートコードの単体テスト

MVCパターンを設計します。モデルの変更についてコントローラに通知するために、デリゲートパターンまたはKey-Value-Observing(KVO)として設計できます。プロジェクトでは、これらの検証文書に準拠するために特定の品質管理手順が必要です。

私の質問:

  1. デリゲートパターンは、KVOよりも単体テストに適していますか?

  2. KVOの方が適している場合は、いくつかのサンプルコードを提案してください。

3
ZhangChn

これは間違った質問だと思います。デリゲート、KVO、および通知はすべて単体テストできます。オブジェクトが互いにどのように相互作用するかを選択するとき、それは主要な関心事ではありません。

解決しようとしている問題に適したパターンを選択してください。たとえば、Appleはデリゲートを使用して、UITableViewがコントローラーから情報をプルできるようにします。これは適切だと感じます。テーブルビューは必要な情報を認識し、その情報をデリゲートからプルします。

Appleは、UITableViewに通知を送信させることを選択できたはずです。テーブルビューがUITableViewCellForRowAtIndexPathNotificationを送信せず、サブスクライバーがユーザー情報に含まれるインデックスパスにセルを設定することを期待する技術的な理由はありません。それが適切ではないので、彼らはこれをしませんでした。

一般的に、デリゲートは真実の情報源から情報を引き出すのに適しています。ビューはこれを使用して、表示に必要な詳細を収集します。通知とKVOは、信頼できる情報源から情報を適切にプッシュします。モデルはこれを使用して、システムの他の部分が知る必要があるかもしれない変更をアナウンスします。


[〜#〜] update [〜#〜]

もう一度質問を読んだところ、KVOを使いたいようです。単体テストのコードについては、これを行う方法を示すコードをいくつか示します。

モデルのプロパティの変更を監視しているコントローラーをテストしようとしていると仮定します。変更が観察されると、コントローラーはビューのテキストを変更します。コントローラーには、modelおよびtextViewという名前のプロパティがあります。モデルにはプロパティ名propがあります。 TextViewには、textという名前のプロパティがあります。コントローラは[self addObserver:self forKeyPath:@"model.prop" options:0 context:NULL]を呼び出してKVOを実行します。

FakeModel *fakeModel = [[FakeModel alloc] init]; // FakeModel stubs out the needed functionality of Model.
FakeTextView *fakeTextView = [[FakeTextView alloc] init]; // FakeTextView stubs out the needed functionality of TextView.

Controller *controller = [storyboard instantiateViewControllerWithIdentifier:@"controller"]; // Or however you create your controller.
controller.textView = fakeTextView;
controller.model = fakeModel;

fakeModel.prop = @"new value"; // Change model.prop to kick off the KVO and change textview.text.

STAssertEqualObjects(fakeTextView.text, @"expected new text", @"Text should have matched");

もちろん、プロジェクトにOCMockがある場合は、これにOCMockを使用できます。

お役に立てば幸いです。

3
Jeffery Thomas

提案されたアプローチはどちらも「単体テストには適していません」。デリゲート、KVO、コールバックブロック、通知、またはその他のスキームを使用できます。これらのすべてをテストできます。

私の経験でテスト可能なコードを書くための鍵は、 テスト駆動開発 とその赤緑リファクタリングのマントラのように、最初にテストを書くことです。そうすれば、テストがすでに存在し、統合するコードを書く必要があるという事実によって(簡単に)テストできるコードを書くことが制約されますそれと。

最初にコードを記述し、、次にをテストしてみると、小規模ではありますが、既存のコードを統合しようとするのと同じ問題があります。 。テストがクラスとインターフェイスする必要がある場所、クラスがそのインターフェイスを提供するかどうか、クラスがインターフェイスがそのように使用されることを期待するかどうかを判断する必要があります... TDDの主要な側面は、必要なインターフェイスを作成することですwhen必要な場合は、改造するのではなく、必要です。

1
user4051

デリゲートのアプローチは、元のコードを変更(またはパフォーマンスのヒロイック)することなく、デリゲートをモックしてそのモックを使用できるため、単体テストが簡単です。

1
kamprath