【发布时间】:2013-06-06 23:15:57
【问题描述】:
我刚刚阅读了以下帖子并尝试实施其中描述的方法:
Writing iOS acceptance tests using Kiwi - Being Agile
那里描述的所有东西都可以完美运行。但!当我运行验收测试时,有一件事会破坏确定性。
这里是 Github 上的 repo,该帖子的作者推送了他的实验(可以在 cmets 的页面底部找到):https://github.com/moredip/2012-Olympics-iOS--iPad-and-iPhone--source-code/tree/kiwi-acceptance-mk1
考虑一下他用于点击视图的这段代码:
- (void) tapViewViaSelector:(NSString *)viewSelector{
[UIAutomationBridge tapView:[self viewViaSelector:viewSelector]];
sleepFor(0.1); //ugh
}
...sleepFor 有 following definition behind itself:
#define sleepFor(interval) (CFRunLoopRunInMode(kCFRunLoopDefaultMode, interval, false))
等待一小段时间直到所有动画都被处理并浸泡是一种天真的尝试(“天真”不是关于作者,而是关于它是第一个进入脑海的事实)已(或可能)安排到主运行循环的所有可能事件(另请参阅this comment)。
问题是这个幼稚的代码不能以确定性的方式工作。有一堆 UI 交互会导致在当前编辑的文本字段的键盘消失之前按下 fx 下一个按钮,等等......
如果我只是将时间从 0.1 增加到 fx 1,所有问题都会消失,但这会导致每一个交互,如“用文本填充文本字段......”或“点击带有标题的按钮......”变成花费一秒钟!
所以我的意思不仅仅是在这里增加等待时间,而是一种进行这种人为等待的方法来保证我可以继续我的测试用例进行下一步。
我希望它应该是一种更可靠的方法,可以等待足够长的时间,直到当前操作引起的所有内容(所有过渡/动画或任何主运行循环内容)都完成。
总结为一个问题:
有没有办法耗尽/排空/浸泡所有调度到主线程及其运行循环的内容,以确保主线程处于空闲状态且其运行循环为“空”?
这是我最初的解决方案:
// DON'T like it
static inline void runLoopIfNeeded() {
// https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFRunLoopRef/Reference/reference.html
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES) == kCFRunLoopRunHandledSource);
// DON'T like it
if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES) == kCFRunLoopRunHandledSource) runLoopIfNeeded();
}
【问题讨论】:
标签: ios objective-c runloop