【问题标题】:Xcode 7 UI Testing: Dismiss Push and Location alertsXcode 7 UI 测试:关闭推送和位置警报
【发布时间】:2016-02-25 19:27:23
【问题描述】:

我在使用 Xcode 7 UI 测试时遇到了问题。

我的用户登录后,该应用会显示两个警报,请求位置警报和推送通知警报。这些通知一个接一个地显示。位置首先出现。

我尝试自动关闭它们以开始我的测试。

为此,我添加了两个UIInterruptionMonitor,第一个用于位置警报,第二个用于通知推送警报。

    addUIInterruptionMonitorWithDescription("Location Dialog") { (alert) -> Bool in
        /* Dismiss Location Dialog */
        if alert.collectionViews.buttons["Allow"].exists {
            alert.collectionViews.buttons["Allow"].tap()
            return true
        }
        return false
    }
    addUIInterruptionMonitorWithDescription("Push Dialog") { (alert) -> Bool in
        /* Dismiss Push Dialog */
        if alert.collectionViews.buttons["OK"].exists {
            alert.collectionViews.buttons["OK"].tap()
            return true
        }
        return false
    }

但只有位置一被触发,推送通知的处理程序UIInterruptionMonitor永远不会被调用。

如果我在 Request Location UIInterruptionMonitor 中返回 true,正如 this other post accepted answer 指定的那样。两个处理程序都被调用,但两个 UIInterruptionMonitor 中的 alert 参数链接到 Request Location 警报视图,因此永远找不到“确定”按钮。

如何关闭这两个连续的警报视图?

【问题讨论】:

  • 我正在处理完全相同的问题,但尚未找到解决方案。我尝试只使用一个并在两者中检查“允许”和“确定”,但这也不起作用....
  • 我这几天一直在纠结这个问题。你有什么进展吗?太令人沮丧了
  • 我也遇到了这个问题。一个警报?没问题。两个连续的警报 => 只有 1 个被点击。

标签: ios xcode swift xcode-ui-testing


【解决方案1】:

虽然不理想,但我发现如果您只是等到一个授权对话框完成后再在应用中显示另一个授权对话框,UI 测试可以连续接收多个请求。

    if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse || CLLocationManager.authorizationStatus() == .AuthorizedAlways {
        self.locationManager.requestLocation()
    } else {
        self.contactStore.requestAccessForEntityType(.Contacts) { _ in
            self.locationManager.requestWhenInUseAuthorization()
        }
    }

我实际上是在我的代码中请求访问不同位置的联系人,但它可以很好地处理多个同时请求。

然后在我的测试中:

    addUIInterruptionMonitorWithDescription("Location Dialog") { (alert) -> Bool in
        let button = alert.buttons["Allow"]
        if button.exists {
            button.tap()
            return true
        }
        return false
    }
    addUIInterruptionMonitorWithDescription("Contacts Dialog") { (alert) -> Bool in
        let button = alert.buttons["OK"]
        if button.exists {
            button.tap()
            return true
        }
        return false
    }

    app.buttons["Location"].tap()

    app.tap() // need to interact with the app for the handler to fire
    app.tap() // need to interact with the app for the handler to fire

【讨论】:

    【解决方案2】:

    正如我在the answer you mentioned 中指出的,您必须在警报出现后与应用程序进行交互。

    其次,在呈现警报后,您必须与界面进行交互。只需点按应用即可,但这是必需的。

    // add UI interruption handlers
    
    app.buttons["Request Location"].tap()
    app.tap() // need to interact with the app for the handler to fire
    

    【讨论】:

    • 我尝试按照您说的做,但没有成功。为了解决我的问题,我不得不延迟两个警报之一。
    • 太棒了!如果这对您有用,请接受答案,以便其他人知道它应该对他们有用。
    • 你是如何添加延迟的?
    【解决方案3】:
    class BaseTest: XCTestCase {
        let pushSent = NSNotification.Name.init("alert.pushSent")
        var notificationMonitor: NSObjectProtocol?
    
        override func setUp() {
            listenNotifications()
            let app = XCUIApplication()
    
            notificationMonitor = addUIInterruptionMonitor(withDescription: "Push Notifications") { [unowned self] (alert) -> Bool in
                let btnAllow = app.buttons["Allow"]
                //1:
                if btnAllow.exists {
                    btnAllow.tap()
                    NotificationCenter.default.post(name: self.pushSent, object: nil)
                    return true
                }
                //2:
                //takeScreenshot
                XCTFail("Unexpected System Alert")
                return false
            }
            //3:
            //add code for "Request Location" monitor
    
            app.launchEnvironment = ["UITEST_DISABLE_ANIMATIONS" : "YES"]
            //4:
            app.launch()
    
        }
    
        func listenNotifications() {
            NotificationCenter.default.addObserver(forName: pushSent, object: nil, queue: nil) { (notification) in
                if let locationDialogHandeler = self.notificationMonitor {
                    //5:
                    self.removeUIInterruptionMonitor(locationDialogHandeler)
                }
            }
        }
    }
    

    1:检查您是否处于正确的警报中,点击按钮并找到移除显示器的方法(我正在使用 NotificationCenter)

    2:如果你进入一个监视器,却找不到正确的按钮,这意味着它是一个意外的流程。测试失败(但先截屏)。

    3:添加其他监视器

    4:我什至在启动应用程序之前添加了监视器。如果在警报出现后添加监视器,则不会触发。

    5:移除监视器,这样当出现新警报时,将调用堆栈中的下一个监视器。

    P.S:您应该以相反的顺序添加监视器,因此,在“推送通知”之后添加“请求位置”

    【讨论】:

      【解决方案4】:

      要关闭系统警报视图(即:推送通知),您可以define custom flags for the testing environment

      然后,您只需更改应用程序的代码以避免特定的初始化(即:推送通知):

      #if !TESTING
      let settings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
      application.registerUserNotificationSettings(settings)
      #endif
      

      我使用这个技巧是为了能够用snapshot截屏。

      【讨论】:

      • 这并没有解决问题,只是禁用了应用程序中的一项功能。
      • 问题是:“我怎样才能关闭这两个连续的警报视图?”
      猜你喜欢
      • 1970-01-01
      • 2015-10-23
      • 1970-01-01
      • 1970-01-01
      • 2016-08-13
      • 2019-11-10
      • 1970-01-01
      • 2015-11-15
      • 2015-12-10
      相关资源
      最近更新 更多