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

在iOS应用程序的UI测试中禁用等待空闲状态,ios,xcode-ui-testing,Ios,Xcode Ui Testing,问题基本上与此相同: 我在视图中不断重复使用“背景动画”。这个!@$$$&@Xcode/iOS的UI测试需要等待所有UIView动画结束,然后才考虑应用程序空闲,并继续进行点击按钮等操作。这与我们设计应用程序的方式不符。(特别是,我们有一个按钮,它使用UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse选项设置动画,因此它永远不会停止。) 但我认为可能有某种方法可以关闭和/或缩短“等待应用程序空闲”状态。有?怎么用?有其他办

问题基本上与此相同:

我在视图中不断重复使用“背景动画”。这个!@$$$&@Xcode/iOS的UI测试需要等待所有UIView动画结束,然后才考虑应用程序空闲,并继续进行点击按钮等操作。这与我们设计应用程序的方式不符。(特别是,我们有一个按钮,它使用
UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse
选项设置动画,因此它永远不会停止。)


但我认为可能有某种方法可以关闭和/或缩短“等待应用程序空闲”状态。有?怎么用?有其他办法吗?

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

如果您只想在特定视图中禁用该特定视图的动画,或者在代理文件中禁用整个应用程序的动画,则可以将该复选框放置在特定视图中。

您实际上可以禁用
等待应用程序空闲。这是一次黑客攻击,可能不稳定。禁用动画,并且启用此黑客攻击,我看到大约20%的性能提升(在禁用动画的性能提升之上)

你所要做的就是关闭调用的方法,使应用程序空闲,而不运行它。该方法是
xguiapplicationprocesswaitforquiesceincludinganizationsidle:

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

注意
等待应用程序空闲
将不再出现在日志中

我在Objective-C中使用了GH123人答案,以防有人需要:

- (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
}

我在Objective-C中使用了h.w.powers的解决方案,以防有人需要

设置:

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
}

我在几个测试类的setUp()中使用了gh123man的解决方案,在升级到ios13.3之前,它一直很有魅力。从那时起,应用程序就陷入了启动状态

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

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

谢谢,这就是我现在要做的。这并不完美,但可能是目前唯一的办法。可以告诉动画只运行一次迭代等。只是为了澄清,应该是
让app=xguiapplication()app.launchenEnvironment=[“UITEST\u DISABLE\u Animations:“YES”]app.launch()
我一直在试图弄清楚发生了什么,这就是问题所在,谢谢!!工作起来很有魅力!此外,您可以提到,由于这一点,在某些情况下,有必要使用
waitForExistence
功能–因为速度;)哦,天哪,这太棒了。80年代的测试都是“等待应用程序空闲”的废话,现在它做了我希望它做的事情,在iOS 13.1和XCode 11.1的iPad上运行良好,谢谢。@gh123man有没有办法对Android做同样的事情?这并没有提供问题的答案。您可以,也可以参考页面右侧的相关和链接问题来找到答案。如果您有一个相关但不同的问题,并包含指向此问题的链接以帮助提供上下文。请参阅:感谢您对U10转发的评论。我找到了一个方法使它工作,并更新了我的答案。