我遇到了Xcode 7 UI测试的问题。
我的用户登录后,应用程序会显示两个警报,即请求位置警报和推送通知警报。这些通知一个接一个地显示。位置一出现在第一位。
我尝试自动解雇它们以开始我的测试。
为此,我添加了两个ADDUIInterruptionMonitor,第一个用于Location Alert,第二个用于Notification Push Alert。
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
}
但只触发Location 1,从不调用Push Notifications UIInterruptionMonitor的处理程序。
如果我在请求位置UIInterruptionMonitor中返回true,就像this other post accepted answer指定的那样。两个处理程序都被调用,但两个UIInterruptionMonitor中的alert参数都链接到请求位置警报视图,因此永远找不到“确定”按钮。
如何解除这两个连续的警报视图?
虽然不理想,但我发现如果您只是等到一个授权对话框完成后再在应用程序中显示另一个授权对话框,则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
正如我在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
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:您应该以相反的顺序添加监视器,因此,在“推送通知”之后添加“请求位置”
要解除系统警报视图(即:推送通知),您可以define custom flags for the testing environment。
然后,您只需更改应用程序的代码以避免特定的初始化(即:推送通知):
#if !TESTING
let settings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
#endif
我使用这个技巧,以便能够使用snapshot截取屏幕截图。