在 TDD 之后,我正在开发一个 iPad 应用程序,该应用程序从 Internet 下载一些信息并将其显示在列表中,允许用户使用搜索栏过滤该列表。
我想测试一下,当用户在搜索栏中键入时,带有过滤器文本的内部变量会更新,过滤后的项目列表也会更新,最后表格视图会收到“reloadData”消息。
这些是我的测试:
- (void)testSutChangesFilterTextWhenSearchBarTextChanges
{
// given
sut.filterText = @"previous text";
// when
[sut searchBar:nil textDidChange:@"new text"];
// then
assertThat(sut.filterText, is(equalTo(@"new text")));
}
- (void)testSutReloadsTableViewDataAfterChangeFilterTextFromSearchBar
{
// given
sut.tableView = mock([UITableView class]);
// when
[sut searchBar:nil textDidChange:@"new text"];
// then
[verify(sut.tableView) reloadData];
}
注意:更改“filterText”属性现在会触发实际的过滤过程,该过程已在其他测试中进行了测试。
这可以正常工作,因为我的 searchBar 委托代码编写如下:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
self.filterText = searchText;
[self.tableView reloadData];
}
问题是过滤这些数据正在成为一个繁重的过程,目前正在主线程上完成,因此在此期间 UI 被阻塞。
因此,我想到了做这样的事情:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSArray *filteredData = [self filteredDataWithText:searchText];
dispatch_async(dispatch_get_main_queue(), ^{
self.filteredData = filteredData;
[self.tableView reloadData];
});
});
}
这样过滤过程发生在不同的线程中,当它完成时,表被要求重新加载它的数据。
问题是......我如何在 dispatch_async 调用中测试这些东西?
除了基于时间的解决方案之外,还有其他优雅的方法吗?(比如等待一段时间并期望这些任务已经完成,不是很确定)
或者也许我应该把我的代码放在不同的方式上,让它更容易测试?
如果您需要知道,我正在使用Jon Reid的OCMockito和OCHamcrest。
提前致谢!!