在iOS应用程序的UI测试中禁用等待空闲状态

问题描述 投票:0回答:7

基本上问题与此相同:XCTestCase:等待应用程序空闲

我在我的视图中不断重复使用“背景动画”。 Xcode/iOS 的 UI 测试希望等待所有 UIView 动画结束,然后才认为应用程序空闲并继续进行点击按钮等操作。它只是不符合我们设计应用程序的方式。 (具体来说,我们有一个带有

UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse
选项的动画按钮,因此它永远不会停止。)

但我认为可能有某种方法可以关闭和/或缩短“等待应用程序空闲”状态。有没有?如何?有没有其他办法解决这个问题?

ios xcode-ui-testing
7个回答
34
投票

您实际上可以禁用

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
将不再出现在日志中。


14
投票

不幸的是,使用 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)
}

如果您只希望它禁用特定视图的动画,则可以将该检查放置在特定视图中,或者放置在委托文件中以禁用整个应用程序的动画。


4
投票

我在 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
}

0
投票

我在几个测试类的 setUp() 中使用了 gh123man 的解决方案,在更新到 iOS 13.3 之前它一直很有效。从那时起应用程序陷入启动状态。

发现如果我将其移动到像disableWaitForIdle()和enableWaitForIdle()这样的方法并仅以最精细的方式调用它们(在我知道应用程序永远不会空闲的点击之前和之后),它仍然有效,例如像这样:

@discardableResult func selectOption() -> Self {
    disableWaitForIdle()
    app.cells["Option"].firstMatch.waitAndForceTap(timeout: 20)
    enableWaitForIdle()
    return self
}

0
投票

我翻译成 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
}

0
投票

对于间歇性遇到这个

wait for app to idle
问题的人,我在运行本地 XCUITests 时也经历过几次。退出并重新打开模拟器对我来说已经成功了,但不确定到底为什么。模拟器运行两周后,也许系统 UIKit 的一些东西会变得古怪。


0
投票

使用 wdio/appium 解决方案对我有帮助的是添加功能 'appium:waitForIdleTimeout': 0,没有它每个操作(如单击)需要 20 秒。

© www.soinside.com 2019 - 2024. All rights reserved.