Xcode 7用户界面testing:如何解除代码中的一系列系统警报

我正在编写使用新的Xcode 7 UItestingfunction的UItesting用例。 在我的应用程序的某个时候,我要求用户许可摄像头访问和推送通知。 因此,两个iOSpopup窗口将显示: "MyApp Would Like to Access the Camera"popup窗口和"MyApp Would Like to Send You Notifications"popup。 我想我的testing,以消除这两个popup窗口。

UIlogging为我生成了以下代码:

 [app.alerts[@"cameraAccessTitle"].collectionViews.buttons[@"OK"] tap]; 

但是, [app.alerts[@"cameraAccessTitle"] exists]parsing为false,上面的代码生成一个错误: Assertion Failure: UI Testing Failure - Failure getting refresh snapshot Error Domain=XCTestManagerErrorDomain Code=13 "Error copying attributes -25202"

那么在testing中解除一堆系统警报的最好方法是什么? 系统popup窗口中断我的应用程序stream程,并立即失败我的正常UItesting用例。 事实上,有关如何绕过系统警报的任何build议,所以我可以恢复testing通常的stream程,赞赏。

这个问题可能与这个SOpost有关,也没有答案: Xcode7 | Xcode UItesting| 如何处理位置服务警报?

提前致谢。

Xcode 7.1

Xcode 7.1终于解决了系统警报的问题。 然而,有两个小陷阱。

首先,您需要在显示警报之前设置一个“UI Interuption Handler”。 这是我们告诉框架在出现时如何处理警报的方式。

其次,在显示警报之后,您必须与界面进行交互。 简单地点击应用程序工作得很好,但是是必需的。

 addUIInterruptionMonitorWithDescription("Location Dialog") { (alert) -> Bool in alert.buttons["Allow"].tap() return true } app.buttons["Request Location"].tap() app.tap() // need to interact with the app for the handler to fire 

“位置对话框”只是一个string,用于帮助开发人员识别哪个处理程序被访问过,而不是特定于警报的types。

我相信从处理程序返回true表示它是“完整的”,这意味着它不会再被调用。 对于你的情况,我会尝试返回false所以第二个警报将再次触发处理程序。

Xcode 7.0

以下将closuresXcode 7 Beta 6中的一个“系统警报”:

 let app = XCUIApplication() app.launch() // trigger location permission dialog app.alerts.element.collectionViews.buttons["Allow"].tap() 

Beta 6为UItesting引入了一系列修复,我相信这是其中之一。

还要注意,我直接在-alerts上调用-alerts 。 在XCUIElementQuery上调用XCUIElementQuery强制框架在屏幕上select“唯一”的匹配元素。 这对于一次只能有一个可见的警报很有用。 但是,如果您尝试使用这个标签并且有两个标签,框架将会引发exception。

天哪。 它总是点击“不允许”,即使我故意说点击“允许”

至less

 ` if app.alerts.element.collectionViews.buttons["Allow"].exists { app.tap() }` 

允许我继续前进,并做其他testing。

神! 我讨厌XCTest最糟糕的时间处理UIView警报。 我有一个应用程序,我得到2警报第一个要我select“允许”启用位置服务的应用程序的权限,然后在启动页面用户不得不按下UIButton称为“打开位置”,最后有一个在UIViewAlert中通知短信提醒,用户必须select“确定”。 我们遇到的问题是无法与系统警报进行交互,但也是一种竞争状态,在屏幕上的行为和外观是不合时宜的。 看来如果你使用alert.element.buttons["whateverText"].tap XCTest的逻辑就是保持按下直到testing时间结束。 所以基本上一直按住屏幕上的任何东西,直到所有的系统警报都清晰可见。

这是一个黑客,但这是为我工作。

  func testGetPastTheStupidAlerts(){ let app = XCUIApplication() app.launch() if app.alerts.element.collectionViews.buttons["Allow"].exists { app.tap() } app.buttons["TURN ON MY LOCATION"].tap() } 

string“允许”被完全忽略, app.tap()的逻辑被称为evreytime,一个警报在视图中,最后我想要达到的button[“打开位置”]可以访问,testing通过

〜完全困惑,谢谢苹果。

目标 – C

 -(void) registerHandlerforDescription: (NSString*) description { [self addUIInterruptionMonitorWithDescription:description handler:^BOOL(XCUIElement * _Nonnull interruptingElement) { XCUIElement *element = interruptingElement; XCUIElement *allow = element.buttons[@"Allow"]; XCUIElement *ok = element.buttons[@"OK"]; if ([ok exists]) { [ok tap]; return YES; } if ([allow exists]) { [allow tap]; return YES; } return NO; }]; } -(void)setUp { [super setUp]; self.continueAfterFailure = NO; self.app = [[XCUIApplication alloc] init]; [self.app launch]; [self registerHandlerforDescription:@"“MyApp” would like to make data available to nearby Bluetooth devices even when you're not using app."]; [self registerHandlerforDescription:@"“MyApp” Would Like to Access Your Photos"]; [self registerHandlerforDescription:@"“MyApp” Would Like to Access the Camera"]; } 

迅速

 addUIInterruptionMonitorWithDescription("Description") { (alert) -> Bool in alert.buttons["Allow"].tap() alert.buttons["OK"].tap() return true } 

我发现的唯一可靠的解决方法是设置两个单独的testing来处理警报。 在第一个testing中,我打电话给app.tap() ,不做别的。 在第二个testing中,我再次调用app.tap() ,然后做真正的工作。

听起来就像实现摄像头访问的方法,通知按照您的说法进行线程化处理,但没有进行物理上的pipe理,只是在显示时显示方式。

我怀疑其中一个是由另一个触发的,当它以编程方式点击时,它也会擦除另一个(Apple可能永远不会允许)

想想看,你要求用户许可,然后代表他们作出决定? 为什么? 因为你可能无法让你的代码工作。

如何解决 – 跟踪这两个组件触发popup对话框的位置 – 被调用的位置?重写为只触发一个,当一个对话框完成时发送NSNotification触发并显示剩余的对话框。

我会严重阻碍编程方式为用户点击对话button的方法。