2013-09-29 60 views
0

我試圖嘲笑和測試UITableViewCells,以確保我的configureCell:forIndexPath工作正常,除了我不能讓它使用isKindOfClass工作,但只conformsToProtocol。這將需要我所有的uitableviewcells都有它自己的協議,而且看起來並不需要。嘲笑UITableViewCell和使用isKindOfClass

- (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存根] andReturnValue:OCMOCK_VALUE((BOOL){} YES)] isKindOfClass:[MyTableViewCell類]]]用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。

有沒有辦法做到這一點,或者我必須使用每個tableviewcell協議?在此先感謝

+1

什麼是configureCell方法定義?它是否使用MyTableViewCell *作爲傳遞的單元格? –

+0

MyTableViewCell絕對是UITableViewCell的子類嗎? –

+0

我已經添加了configureCell方法定義,並且是MyTableViewCell絕對是UITableViewCell的一個子類。我使用的是xib,我擴展了UITableViewCell,並將xib中的類名設置爲MyTableViewCell – user2828419

回答

1

我強烈建議您重新考慮如何構建此實現。對於初學者來說,視圖控制器在管理視圖方面非常出色,但管理模型數據並不是它的目的。它很適合將模型數據傳遞給它所管理的視圖,所以考慮到這一點,讓我們來構建它。

我們首先介紹一個名爲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測試框架,並測試您的用戶界面。使用FeedController上的單元測試來測試您的數據和轉換。

我希望這會有所幫助。

+0

我會試一試! – user2828419

+1

我將此標記爲正確的答案,因爲此模式確實有效。謝謝! – user2828419