0

UITableViewCells をモックおよびテストして、configureCell:forIndexPath が正しく動作することを確認しようとしていますが、isKindOfClass を使用して動作させることはできず、conformsToProtocol のみを使用して動作させることはできません。これには、すべての uitableviewcells に独自のプロトコルが必要であり、必要ないようです。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
  FeedObj *item = [_feedElements objectAtIndex:indexPath.row];
  if( item.obj_type == FeedObjTypeFriendAdd ) {
    MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyTableViewCellIdentifier forIndexPath:indexPath];
    [self configureCell:cell forIndexPath:indexPath]
    return cell;
  } else if( item.obj_type = FeedObjTypeSomeOtherType ) {
    // do another cell
  }
}

- (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath 
{
  // only enters conditional in test if I do [cell conformsToProtocol:@protocol(SomeIndividualProtocolForEachTableViewcell)]                  
  if( [cell isKindOfClass:[MyTableViewCell class]] ) {
    // do the configuring
    FeedObj *item = [_streamElements objectAtIndex:indexPath.row];

    NSString *firstName = [item.obj_data objectForKey:@"first_name"];
    NSString *lastName = [item.obj_data objectForKey:@"last_name"];
    NSString *name = [NSString stringWithFormat:@"%@ %@.", firstName, [lastName substringToIndex:1]];
    NSString *text = [NSString stringWithFormat:@"%@ has joined", name];

    [((MyTableViewCell *)cell).messageLabel setText:text];

  } else if( [cell isKindOfClass[SomeOtherTableView class]] ) {
    // do other config
  }
}


    @implementation SampleTests
    - (void)setUp
    {
        _controller = [[MySampleViewController alloc] init];
        _tableViewMock = [OCMockObject niceMockForClass:[UITableView class]];
        [_tableViewMock registerNib:[UINib nibWithNibName:@"MyTableViewCell" bundle:nil] forCellReuseIdentifier:MyTableViewCellIdentifier];
    }

    - (void)testFriendAddCell
    {
        FeedObj *friendAdd = [[FeedObj alloc] init];
        friendAdd.obj_type = FeedObjTypeFriendAdd;
        friendAdd.obj_data = [NSMutableDictionary dictionaryWithDictionary:@{ @"first_name" : @"firstname", @"last_name" : @"lastname" }];
        _mockStreamElements = [NSMutableArray arrayWithObject:friendAdd];
        [_controller setValue:_mockStreamElements forKey:@"_feedElements"];

        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
        [[[_tableViewMock expect] andReturn:[[[NSBundle mainBundle] loadNibNamed:@"MyTableViewCell" owner:self options:nil] lastObject]] dequeueReusableCellWithIdentifier:MyTableViewCellIdentifier forIndexPath:indexPath];

        MyTableViewCell *cell = (MyTableViewCell *)[_controller tableView:_tableViewMock cellForRowAtIndexPath:indexPath];
        STAssertNotNil( cell, @"should not be nil" );
        STAssertTrue( [cell.messageLabel.text isEqualToString:@"firstname l. has joined"], @"should be equal" );
        [_tableViewMock verify];
    }
    @end

また、 [[[mockCell stub] andReturnValue:OCMOCK_VALUE((BOOL) {YES})] isKindOfClass:[MyTableViewCell class]]] を mockCell 期待値で実行しようとしましたが、どちらも機能しません。このような:

id mockCell = [OCMockObject partialMockForObject:[[[NSBundle mainBundle] loadNibNamed:@"MyTableViewCell" owner:self options:nil] lastObject]];
[[[mockCell stub] andReturnValue:OCMOCK_VALUE((BOOL) {YES})] isKindOfClass:[OCMConstraint isKindOfClass:[MyTableViewCell class]]];
[[[_tableViewMock expect] andReturn:mockCell] dequeueReusableCellWithIdentifier:MyTableViewCellIdentifier forIndexPath:indexPath];

http://blog.carbonfive.com/2009/02/17/custom-constraints-for-ocmock/にリストされている OCMConstraint を試してみました。

これを行う方法はありますか、それともテーブルビューセルごとにプロトコルを使用する必要がありますか? 前もって感謝します

4

1 に答える 1

1

この実装を構築する方法を再考することを強くお勧めします。まず第一に、View Controller はビューの管理には優れていますが、モデル データの管理は目的ではありません。モデルデータを管理するビューに渡すのに適しているので、それを念頭に置いて、そのように構築しましょう。

という名前の新しいクラスを導入することから始めましょうFeedController。このコントローラーの仕事は、VC と、この画面を支えるモデル データの間に位置することです。この公開インターフェースを想定してみましょう:

@interface FeedController : NSObject
- (instancetype)initWithFeedArray:(NSArray *)array;
- (NSString *)firstNameAtIndexPath:(NSIndexPath *)path;
- (NSString *)lastNameAtIndexPath:(NSIndexPath *)path;
- (NSString *)fullNameAtIndexPath:(NSIndexPath *)path;
// This should probably have a better name
- (NSString *)textAtIndexPath:(NSIndexPath *)path;
@end

これらのメソッドを実装するつもりはありませんが、期待どおりに見えるはずです。初期化子は渡された配列をコピーして ivar に格納し、他のメソッドは特定のインデックスで配列から情報を取り出し、必要なカスタム変換を適用します (姓と名を結合するなど)。フルネームを取得します)。ここでの主な目的は、データを操作することではなく、転送することです。ビュー コントローラでこのデータを操作しようとした瞬間が、賢明なテストで振り出しに戻る瞬間です。

あなたの目的は、テストが非常に簡単なクラスconfigureCell:forIndexPath:からデータを転送することだけです。FeedControllerレスポンダー チェーンをセットアップしたり、オブジェクトをモックアウトしたりする必要はありません。いくつかのフィクスチャ データを提供するだけで、すぐに使用できます。

あなたはまだあなたのメソッドを構成する部分をテストしていますconfigureCell:forIndexPath:が、そのメソッドを直接テストしていません。ビューが正しく取り込まれていることを確認したい場合は、そうすべきです。ただし、これは別の方法で行います。これは単体テストの仕事ではありません。UIAutomationまたはお気に入りの UI テスト フレームワークを引き出して、UI をテストします。の単体テストを使用してFeedController、データと変換をテストします。

これが役立つことを願っています。

于 2013-09-30T21:23:12.610 に答える