基本上问题与此相同:XCTestCase:等待应用程序空闲
我在我的视图中不断重复使用“背景动画”。 Xcode/iOS 的 UI 测试希望等待所有 UIView 动画结束,然后才认为应用程序空闲并继续进行点击按钮等操作。它只是不符合我们设计应用程序的方式。 (具体来说,我们有一个带有
UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse
选项的动画按钮,因此它永远不会停止。)
但我认为可能有某种方法可以关闭和/或缩短“等待应用程序空闲”状态。有没有?如何?有没有其他办法解决这个问题?
您实际上可以禁用
wait for app to idle
。这是一个 hack,可能不稳定。禁用动画并启用此 hack 后,我发现性能提升了约 20%(除了禁用动画带来的性能提升之外)。
您所要做的就是调出用于空闲应用程序并对其进行空操作的方法。这个方法就是
XCUIApplicationProcess waitForQuiescenceIncludingAnimationsIdle:
这是我在 swift 3 中的工作解决方案 - 可能有更好的方法,但这适用于概念证明。
扩展
XCTestCase
类。我会打电话给我的MyTestCase
static var swizzledOutIdle = false
override func setUp() {
if !MyTestCase.swizzledOutIdle { // ensure the swizzle only happens once
let original = class_getInstanceMethod(objc_getClass("XCUIApplicationProcess") as! AnyClass, Selector(("waitForQuiescenceIncludingAnimationsIdle:")))
let replaced = class_getInstanceMethod(type(of: self), #selector(MyTestCase.replace))
method_exchangeImplementations(original, replaced)
MyTestCase.swizzledOutIdle = true
}
super.setUp()
}
@objc func replace() {
return
}
注意
wait for app to idle
将不再出现在日志中。
不幸的是,使用 Apple 的 UI 测试时,您无法打开“等待应用程序空闲”或轮询其他网络活动,但是您可以使用环境变量来禁用应用程序中的动画,以使测试更加稳定。在测试之前在您的设置方法中设置一个像这样的环境变量。
override func setUp() {
super.setUp()
continueAfterFailure = false
let app = XCUIApplication()
app.launchEnvironment = ["UITEST_DISABLE_ANIMATIONS" : "YES"]
app.launch()
}
现在在您的源代码中:
if (ProcessInfo.processInfo.environment["UITEST_DISABLE_ANIMATIONS"] == "YES") {
UIView.setAnimationsEnabled(false)
}
如果您只希望它禁用特定视图的动画,则可以将该检查放置在特定视图中,或者放置在委托文件中以禁用整个应用程序的动画。
我在 Objective-C 中使用了 gh123man 答案,以防有人需要它:
- (void)disableWaitForIdle {
SEL originalSelector = NSSelectorFromString(@"waitForQuiescenceIncludingAnimationsIdle:");
SEL swizzledSelector = @selector(doNothing);
Method originalMethod = class_getInstanceMethod(objc_getClass("XCUIApplicationProcess"), originalSelector);
Method swizzledMethod = class_getInstanceMethod([self class], swizzledSelector);
method_exchangeImplementations(originalMethod, swizzledMethod);
}
- (void)doNothing {
// no-op
}
我在几个测试类的 setUp() 中使用了 gh123man 的解决方案,在更新到 iOS 13.3 之前它一直很有效。从那时起应用程序陷入启动状态。
发现如果我将其移动到像disableWaitForIdle()和enableWaitForIdle()这样的方法并仅以最精细的方式调用它们(在我知道应用程序永远不会空闲的点击之前和之后),它仍然有效,例如像这样:
@discardableResult func selectOption() -> Self {
disableWaitForIdle()
app.cells["Option"].firstMatch.waitAndForceTap(timeout: 20)
enableWaitForIdle()
return self
}
我翻译成 Objective-C,并成功使用了 h.w.powers 的 Swift 解决方案,以防有人需要。
设置:
XCUIApplication *app = [[XCUIApplication alloc] init];
app.launchEnvironment = @{@"UITEST_DISABLE_ANIMATIONS":@"YES"};
[app launch];
然后在你的代码中
if ([[[NSProcessInfo processInfo] environment][@"UITEST_DISABLE_ANIMATIONS"] isEqualToString:@"YES"]) {
// do something like stopping the animation
}
对于间歇性遇到这个
wait for app to idle
问题的人,我在运行本地 XCUITests 时也经历过几次。退出并重新打开模拟器对我来说已经成功了,但不确定到底为什么。模拟器运行两周后,也许系统 UIKit 的一些东西会变得古怪。
使用 wdio/appium 解决方案对我有帮助的是添加功能 'appium:waitForIdleTimeout': 0,没有它每个操作(如单击)需要 20 秒。