我需要模仿UNNotificationResponse
和UNNotification
,以便我可以测试我的实现:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Swift.Void)
但是我无法对这些类进行有用的子类化,因为init()
被明确标记为unavailable
,如果我尝试,会导致编译错误:
/Path/to/PushClientTests.swift:38:5: Cannot override 'init' which has been marked unavailable
这里可采取哪些替代方法?我调查了面向协议的编程路由,但由于我不控制被调用的API,我无法修改它以采用我写的协议。
答案 0 :(得分:1)
要执行此操作,请执行以下操作。
在调试时获取对象的真实示例,并使用模拟器将其保存在文件系统中。
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) {
let encodedObject = NSKeyedArchiver.archivedData(withRootObject: notification)
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/notification.mock"
fileManager.createFile(atPath: path, contents: encodedObject, attributes: nil)
在Mac中找到对象,然后将文件添加到与测试类相同的目标中。
现在在测试中取消存档。
let path = Bundle(for: type(of: self)).path(forResource: "notification", ofType: "mock")
let data = FileManager.default.contents(atPath: path ?? "")
let notification = NSKeyedUnarchiver.unarchiveObject(with: data ?? Data()) as? UNNotification
答案 1 :(得分:1)
如果UNNotificationResponse
的值无关紧要,而您只想执行应用程序委托的方法,则可以通过以下子类化NSKeyedArchiver
来创建模拟来实现此目的:
class MockCoder: NSKeyedArchiver {
override func decodeObject(forKey key: String) -> Any { "" }
}
然后您可以这样称呼它:
let notificationMock = try XCTUnwrap(UNNotificationResponse(coder: MockCoder()))
appDelegate.userNotificationCenter(UNUserNotificationCenter.current(), didReceive: notificationMock) { }
您的应用程序委托的userNotificationCenter(_:didReceive:withCompletionHandler:)
方法现在将被调用,使您可以断言内容(至少假定不针对通知本身进行断言)。
答案 2 :(得分:0)
简短回答:你不能!
相反,分解您的func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Swift.Void)
实现并测试您从那里调用的方法。
快乐测试:)
答案 3 :(得分:0)
您似乎可以初始化UNNotificationContent
个对象。我选择重写我的推送处理方法,以取UNNotificationContent
个UNNotificationResponse
/ UNNotification
对象。
答案 4 :(得分:0)
在iOS上为推送通知实施单元测试时,我使用了下一个扩展来创建UNNotificationResponse和UNNotification实例:
extension UNNotificationResponse {
static func testNotificationResponse(with payloadFilename: String) -> UNNotificationResponse {
let parameters = parametersFromFile(payloadFilename) // 1
let request = notificationRequest(with: parameters) // 2
return UNNotificationResponse(coder: TestNotificationCoder(with: request))! // 3
}
}
这是我上面使用的功能:
extension UNNotificationResponse {
private static func notificationRequest(with parameters: [AnyHashable: Any]) -> UNNotificationRequest {
let notificationContent = UNMutableNotificationContent()
notificationContent.title = "Test Title"
notificationContent.body = "Test Body"
notificationContent.userInfo = parameters
let dateInfo = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: Date())
let trigger = UNCalendarNotificationTrigger(dateMatching: dateInfo, repeats: false)
let notificationRequest = UNNotificationRequest(identifier: "testIdentifier", content: notificationContent, trigger: trigger)
return notificationRequest
}
}
fileprivate class TestNotificationCoder: NSCoder {
private enum FieldKey: String {
case date, request, sourceIdentifier, intentIdentifiers, notification, actionIdentifier, originIdentifier, targetConnectionEndpoint, targetSceneIdentifier
}
private let testIdentifier = "testIdentifier"
private let request: UNNotificationRequest
override var allowsKeyedCoding: Bool { true }
init(with request: UNNotificationRequest) {
self.request = request
}
override func decodeObject(forKey key: String) -> Any? {
let fieldKey = FieldKey(rawValue: key)
switch fieldKey {
case .date:
return Date()
case .request:
return request
case .sourceIdentifier, .actionIdentifier, .originIdentifier:
return testIdentifier
case .notification:
return UNNotification(coder: self)
default:
return nil
}
}
}