Disabling waiting for idle state in UI testing of iOS apps

后端 未结 5 1113
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-02-04 12:37

Basically the problem is the same as this one: XCTestCase: Wait for app to idle

I am using perpetually repeating \"background animations\" in my views. The !@#$#$&@

相关标签:
5条回答
  • 2021-02-04 12:48

    I was using gh123man's solution in setUp() of a couple of test classes and it worked like a charm until updating to iOS 13.3. Since then app gets stuck in launching state.

    Found that it still works if I move it to methods like disableWaitForIdle() and enableWaitForIdle() and call them only in the most granular manner (before and after the tap where I know the app will never become idle), e.g. like this:

    @discardableResult func selectOption() -> Self {
        disableWaitForIdle()
        app.cells["Option"].firstMatch.waitAndForceTap(timeout: 20)
        enableWaitForIdle()
        return self
    }
    
    0 讨论(0)
  • 2021-02-04 12:52

    I used h.w.powers' solution in Objective-C, in case anyone needs it.

    For setting up:

    XCUIApplication *app = [[XCUIApplication alloc] init];
    app.launchEnvironment = @{@"UITEST_DISABLE_ANIMATIONS":@"YES"}; 
    [app launch];
    

    and then in your code

    if ([[[NSProcessInfo processInfo] environment][@"UITEST_DISABLE_ANIMATIONS"] isEqualToString:@"YES"]) {
    // do something like stopping the animation
    }
    
    0 讨论(0)
  • 2021-02-04 12:58

    You actually can disable wait for app to idle. This is a hack and may not be stable. With animations disabled, and this hack enabled I am seeing about a 20% performance gain (on top of the performance boost from disabling animations).

    All you have to do is swizzle out the method that is called to idle the app and no-op it. That method is XCUIApplicationProcess waitForQuiescenceIncludingAnimationsIdle:

    Here is my working solution in swift 3 - there is likely a better way but this works for a proof of concept.

    Extend the XCTestCase class. Ill call mine 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
    }
    

    Note wait for app to idle will no longer appear in the logs.

    0 讨论(0)
  • 2021-02-04 12:59

    Unfortunately using Apple's UI Testing you can't turn 'wait for app to idle' or poll other network activity, however you can use environment variables to disable animations in your app to make the tests more stable. In your setup method before your test set an environment variable like this.

    override func setUp() {
        super.setUp()
        continueAfterFailure = false
        let app = XCUIApplication()
        app.launchEnvironment = ["UITEST_DISABLE_ANIMATIONS" : "YES"]
        app.launch()
    }
    

    Now in your source code:

    if (ProcessInfo.processInfo.environment["UITEST_DISABLE_ANIMATIONS"] == "YES") {
        UIView.setAnimationsEnabled(false)
    }
    

    You can place that check in a specific view if you only want it to disable animations for that specific view or in a delegate file to disable animations throughout the app.

    0 讨论(0)
  • 2021-02-04 13:03

    I used gh123man answer in Objective-C in case anyone needs it:

    - (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 讨论(0)
提交回复
热议问题