我有UITableView
,它有委托和分离的数据源。 DataSource是NSObject
- ArrayDataSource
类的子类。
#import <Foundation/Foundation.h>
typedef void (^ConfigureCellBlock)(id cell, id object);
@interface ArrayDataSource : NSObject <UITableViewDataSource>
@property (nonatomic, readonly) NSArray *items;
@property (nonatomic, readonly) NSString *cellIdentifier;
- initWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier configureCellBlock:(ConfigureCellBlock)block;
- (void)setItems:(NSArray *)items;
- (void)setCellIdentifier:(NSString *)cellIdentifier;
- (void)setConfigureCellBlock:(ConfigureCellBlock)block;
@end
#import "ArrayDataSource.h"
@interface ArrayDataSource ()
@property (nonatomic, copy) ConfigureCellBlock configureCellBlock;
@end
@implementation ArrayDataSource {
NSArray *_items;
NSString *_cellIdentifier;
}
#pragma mark - External
- (id)initWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier configureCellBlock:(ConfigureCellBlock)block {
self = [super init];
if (self) {
_items = items;
_cellIdentifier = cellIdentifier;
_configureCellBlock = [block copy];
}
return self;
}
- (void)setItems:(NSArray *)items {
_items = items;
}
- (void)setCellIdentifier:(NSString *)cellIdentifier {
_cellIdentifier = cellIdentifier;
}
- (void)setConfigureCellBlock:(ConfigureCellBlock)block {
_configureCellBlock = block;
}
#pragma mark - Private
- (id)_itemAtIndexPath:(NSIndexPath *)indexPath {
return _items[indexPath.row];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
id cell = [tableView dequeueReusableCellWithIdentifier:_cellIdentifier forIndexPath:indexPath];
id item = [self _itemAtIndexPath:indexPath];
_configureCellBlock(cell, item);
return cell;
}
#pragma mark - Accessors
- (NSArray *)items {
return _items;
}
- (NSString *)cellIdentifier {
return _cellIdentifier;
}
@end
现在我想测试ConfigureCellBlock
中是否使用正确的参数调用tableView:cellForRowAtIndexPath:
。
我的测试现在看起来像下面但是它没有正常工作,因为它传递并且阻止不会被调用。我的测试类是_tableView
的委托。
#pragma mark - UITableView tests + Delegate + DataSource
- (void)testDataSource {
UITableView *_tableView = [[UITableView alloc] init];
_tableView.delegate = self;
[dataSource setItems:@[@"A"]];
[dataSource setConfigureCellBlock:^(UITableViewCell *cell, NSString *object) {
XCTAssertEqualObjects(object, @"B", @"");
}];
id mockDataSource = [OCMockObject partialMockForObject:dataSource];
SEL selector = NSSelectorFromString(@"_itemAtIndexPath:");
[[[mockDataSource stub] andReturn:dataSource.items[0]] methodForSelector:selector];
_tableView.dataSource = mockDataSource;
UITableViewCell *cell = [[UITableViewCell alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
id mockTableView = [OCMockObject partialMockForObject:_tableView];
[[[mockTableView stub] andReturn:cell] dequeueReusableCellWithIdentifier:OCMOCK_ANY forIndexPath:indexPath];
[mockTableView reloadData];
}
我该如何正确测试?
提前谢谢。
答案 0 :(得分:3)
我通过在块中放置一个标志来测试这种事情:
__block BOOL invoked = NO;
[dataSource setConfigureCellBlock:^(UITableViewCell *cell, NSString *object) {
invoked = YES;
}];
// do something to invoke block...
XCTAssertTrue(invoked, @"configure cell block was not invoked");
在我看来,你正在做很多不必要的嘲弄。我尝试专门针对正在验证的内容集中测试设置,例如发送nil参数以最小化副作用和存根。这是我写的整个测试:
- (void)testDataSource {
[dataSource setItems:@[@"A"]];
__block BOOL invoked = NO;
[dataSource setConfigureCellBlock:^(UITableViewCell *cell, NSString *object) {
XCTAssertEqualObjects(object, @"A", @"got the wrong item");
invoked = YES;
}];
[dataSource tableView:nil cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
XCTAssertTrue(invoked, @"configure cell block was not invoked");
}
答案 1 :(得分:0)
我做到了。如果在-tableView:cellForRowAtIndexPath:
中调用了块,则测试测试:
- (void)testDataSource {
/// Data Source
[dataSource setItems:@[@"A"]];
[dataSource setConfigureCellBlock:^(UITableViewCell *cell, NSString *object) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
XCTAssertNotNil(cell, @"");
XCTAssertEqualObjects(object, @"A", @"");
#pragma clang diagnostic pop
}];
/// Table View
id mockTableView = [OCMockObject niceMockForClass:[UITableView class]];
[[[mockTableView stub] andReturn:dataSource] dataSource];
UITableViewCell *cell = [[UITableViewCell alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[[[mockTableView stub] andReturn:cell] dequeueReusableCellWithIdentifier:OCMOCK_ANY forIndexPath:OCMOCK_ANY];
[[mockTableView dataSource] tableView:mockTableView cellForRowAtIndexPath:indexPath];
}
我使用#pragma
并忽略了有关块中保留周期的警告。我不知道如何在不使用retain-cycles的情况下将断言置于块中。
谢谢@sammyd和@Sebastian。