我正在iOS应用程序中实现推送通知,正如我所做的那样,我想编写一个UI测试,用于验证应用程序在使用某个推送通知负载启动时是否正确(即应用程序导航)到正确的表视图并突出显示正确的单元格)。
可以这样做吗?我似乎无法找到之前已经做过此事或曾经问过这个问题的人。
感谢任何指针。
使用Xcode 9,您现在可以在UITest中实际测试远程通知处理。我使用名为NWPusher的框架实现了它
我写了一篇关于我实现的长blogpost,并向github添加了一个演示项目。
以下是我所做的简短描述:
制备
写下测试
该测试执行以下步骤:
在我的演示中,不同类型的通知会在应用程序中触发不同颜色的模态View Controller。所以我的测试类看起来像这样
import XCTest
import PusherKit
class PushNotificationUITests: XCTestCase {
override func setUp() {
super.setUp()
continueAfterFailure = false
}
func testPushNotifications() {
let app = XCUIApplication()
app.launchArguments.append("isRunningUITests")
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
app.launch()
// dismiss the system dialog if it pops up
allowPushNotificationsIfNeeded()
// get the current deviceToken from the app
let deviceToken = app.staticTexts.element(matching: .any, identifier: "tokenLabel").label
// close app
XCUIDevice.shared.press(XCUIDevice.Button.home)
sleep(1)
// trigger red Push Notification
triggerPushNotification(
withPayload: "{\"aps\":{\"alert\":\"Hello Red\"}, \"vcType\":\"red\"}",
deviceToken: deviceToken)
// tap on the notification when it is received
springboard.otherElements["PUSHNOTIFICATION, now, Hello Red"].tap()
// check if the red view controller is shown
XCTAssert(app.staticTexts["Red"].exists)
// dismiss modal view controller and close app
app.buttons["Close"].tap()
XCUIDevice.shared.press(XCUIDevice.Button.home)
sleep(1)
// trigger green Push Notification
triggerPushNotification(
withPayload: "{\"aps\":{\"alert\":\"Hello Green\"}, \"vcType\":\"green\"}",
deviceToken: deviceToken)
// tap on the notification when it is received
springboard.otherElements["PUSHNOTIFICATION, now, Hello Green"].tap()
// check if the green view controller is shown
XCTAssert(app.staticTexts["Green"].exists)
// dismiss modal view controller and close app
app.buttons["Close"].tap()
XCUIDevice.shared.press(XCUIDevice.Button.home)
sleep(1)
// trigger blue Push Notification
triggerPushNotification(
withPayload: "{\"aps\":{\"alert\":\"Hello Blue\"}, \"vcType\":\"blue\"}",
deviceToken: deviceToken)
// tap on the notification when it is received
springboard.otherElements["PUSHNOTIFICATION, now, Hello Blue"].tap()
// check if the blue view controller is shown
XCTAssert(app.staticTexts["Blue"].exists)
// dismiss modal view controller
app.buttons["Close"].tap()
}
}
extension XCTestCase {
func triggerPushNotification(withPayload payload: String, deviceToken: String) {
let uiTestBundle = Bundle(for: PushNotificationUITests.self)
guard let url = uiTestBundle.url(forResource: "pusher.p12", withExtension: nil) else { return }
do {
let data = try Data(contentsOf: url)
let pusher = try NWPusher.connect(withPKCS12Data: data, password: "pusher", environment: .auto)
try pusher.pushPayload(payload, token: deviceToken, identifier: UInt(arc4random_uniform(UInt32(999))))
} catch {
print(error)
}
}
func allowPushNotificationsIfNeeded() {
addUIInterruptionMonitor(withDescription: "“RemoteNotification” Would Like to Send You Notifications") { (alerts) -> Bool in
if(alerts.buttons["Allow"].exists){
alerts.buttons["Allow"].tap();
}
return true;
}
XCUIApplication().tap()
}
}
这仅适用于物理设备,因为远程通知在模拟器中不起作用。
您可以使用此library发送通知。不幸的是,您应该在AppDelegate
类中添加与测试相关的代码。我在单独的应用程序目标(UITEST=1
)中使用自定义预处理器宏。
你代码中的某个地方:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// ...
#if UITEST
// setup listening
#endif
}
基于joern惊人的文章,我took a step forward并找到了一种以编程方式与收到的通知进行交互的方法,因为它被XCTest框架识别为XCUIElement。
我们可以获得对Springboard的引用
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
例如,当将应用程序放在后台时,我们可以获得对收到的通知的引用(当它显示在屏幕顶部时),如下所示:
let notification = springboard.otherElements["NotificationShortLookView"]
允许我们点按通知:
notification.tap()
将其拉下来查看其操作(如果有的话。通过这样做可以让我们看到Rich Notification的内容):
notification.swipeDown()
与其行动互动:
let action = springboard.buttons["ACTION BUTTON TITLE"]
action.tap()
甚至可以与文本输入通知操作进行交互(在示例中,通过其占位符获取对通知文本字段的引用,您可以在代码中定义):
let notificationTextfield = springboard.textFields["Placeholder"]
notificationTextfield.typeText("this is a test message")
最后,您还可以获取对通知的关闭按钮的引用以解除它:
let closeButton = springboard.buttons["Dismiss"]
closeButton.tap()
通过能够自动化这种交互,我们可以测试,例如分析,如article中所述。