ios - unit - Pruebas de interfaz de usuario de Xcode 7: rechazar las alertas de inserción y ubicación
unit tests swift (4)
Como señalé en la respuesta que mencionó , debe interactuar con la aplicación después de que aparezca la alerta.
Segundo, luego de presentar la alerta debes interactuar con la interfaz. Simplemente tocando la aplicación funciona bien, pero es necesario.
// add UI interruption handlers
app.buttons["Request Location"].tap()
app.tap() // need to interact with the app for the handler to fire
Encontré un problema con Xcode 7 UI Testing.
La aplicación muestra dos alertas después de que mi usuario inicie sesión, la Alerta de ubicación de solicitud y la Alerta de notificaciones push . Esas notificaciones se muestran una tras otra. La ubicación uno aparece primero.
Intento descartarlos automáticamente para iniciar mis pruebas.
Para hacer eso, agrego dos UIInterruptionMonitor , el primero para la alerta de ubicación y el segundo para la alerta de inserción de notificaciones.
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
}
Pero solo se activa la Ubicación uno, nunca se llama al manejador de Notificaciones Push UIInterruptionMonitor .
Si devuelvo verdadero en la ubicación de la solicitud, UIInterruptionMonitor como lo especifica esta otra respuesta aceptada . Se llama a ambos controladores, pero el parámetro de alerta en ambos UIInterruptionMonitor se vincula con la vista de alerta de ubicación de solicitud, por lo que nunca se encuentra el botón "Aceptar".
¿Cómo puedo descartar esas dos vistas de alertas sucesivas?
Para descartar las vistas de alerta del sistema (es decir, Notificación Push ), puede definir indicadores personalizados para el entorno de prueba .
Luego, solo tiene que cambiar el código de la aplicación para evitar inicializaciones específicas (por ejemplo: Notificación Push ):
#if !TESTING
let settings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
#endif
Utilizo este truco para poder tomar capturas de pantalla con snapshot .
Si bien no es lo ideal, descubrí que si simplemente espera hasta que finalice un cuadro de diálogo de autorización antes de presentar otro en la aplicación, las pruebas de la interfaz de usuario pueden detectar múltiples solicitudes seguidas.
if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse || CLLocationManager.authorizationStatus() == .AuthorizedAlways {
self.locationManager.requestLocation()
} else {
self.contactStore.requestAccessForEntityType(.Contacts) { _ in
self.locationManager.requestWhenInUseAuthorization()
}
}
En realidad, estoy solicitando acceso a contactos en un lugar diferente en mi código, pero puede manejar múltiples solicitudes simultáneas muy bien.
Luego en mi prueba:
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
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: Comprueba si estás en la alerta correcta, toca el botón y encuentra una manera de quitar el monitor (estoy usando NotificationCenter)
2: Si ingresa a un monitor y no puede encontrar el botón correcto, significa que es un flujo inesperado. Reprobar la prueba (pero primero tome una captura de pantalla).
3: Añadir otros monitores
4: Estoy agregando monitor incluso antes de iniciar la aplicación. Si agrega un monitor después de que aparezca la alerta, no se activará.
5: Retire el monitor, de esa manera cuando aparezca una nueva alerta, se llamará al siguiente monitor en la pila.
PD: debe agregar monitores en orden inverso, por lo tanto, agregue "Ubicación de solicitud" después de "Notificaciones push"