ser*_*u87 5 unit-testing objective-c objective-c-blocks dispatch-async ocmockito
继TDD之后,我正在开发一款iPad应用程序,可以从互联网上下载一些信息并将其显示在列表中,允许用户使用搜索栏过滤该列表.
我想测试一下,当用户在搜索栏中输入内容时,会更新带有过滤器文本的内部变量,更新过滤的项目列表,最后表格视图会收到"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];
}
Run Code Online (Sandbox Code Playgroud)
注意:更改"filterText"属性现在会触发实际的过滤过程,该过程已在其他测试中进行了测试.
这工作正常,因为我的searchBar委托代码编写如下:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
self.filterText = searchText;
[self.tableView reloadData];
}
Run Code Online (Sandbox Code Playgroud)
问题是过滤这些数据正变成一个繁重的过程,现在正在主线程上完成,因此在此期间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];
});
});
}
Run Code Online (Sandbox Code Playgroud)
因此,过滤过程发生在不同的线程中,当它完成时,要求该表重新加载其数据.
问题是......如何在dispatch_async调用中测试这些内容?
除了基于时间的解决方案之外,还有其他优雅的方法吗?(比如等待一段时间,并期望那些任务已经完成,不是很确定)
或许我应该以不同的方式使我的代码使其更可测试?
如果你需要知道,我使用OCMockito和OCHamcrest由乔恩·里德.
提前致谢!!
有两种基本方法.或
要使事物同步以进行测试,请将实际工作的代码提取到自己的方法中.你已经拥有了-filteredDataWithText:.这是另一个提取:
- (void)updateTableWithFilteredData:(NSArray *)filteredData
{
self.filteredData = filteredData;
[self.tableView reloadData];
}
Run Code Online (Sandbox Code Playgroud)
现在处理所有线程的真正方法如下所示:
- (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 updateTableWithFilteredData:filteredData];
});
});
}
Run Code Online (Sandbox Code Playgroud)
请注意,在所有线程范围之下,它实际上只调用两个方法.所以现在假装所有线程都已完成,让你的测试按顺序调用这两个方法:
NSArray *filteredData = [self filteredDataWithText:searchText];
[self updateTableWithFilteredData:filteredData];
Run Code Online (Sandbox Code Playgroud)
这确实意味着-searchBar:textDidChange:单元测试不会涵盖这一点.单个手动测试可以确认它正在调度正确的东西.
如果您真的想要对委托方法进行自动化测试,请编写一个具有自己的运行循环的验收测试.请参阅模式以获取在完成时调用主队列的单元测试异步队列.(但是将验收测试保存在单独的测试目标中.它们太慢而不能包含单元测试.)
| 归档时间: |
|
| 查看次数: |
2748 次 |
| 最近记录: |