2016-11-29 1 views
6

In meiner App möchte ich feststellen, dass Benachrichtigungen im richtigen Format hinzugefügt wurden. Normalerweise würde ich dies mit Abhängigkeitsinjektionen machen, aber ich kann mir keine Möglichkeit vorstellen, die neue API UNUserNotificationCenter zu testen.Unit Tests iOS 10 Benachrichtigungen

Ich begann ein Mock-Objekt zu erstellen, die die Benachrichtigungsanforderung erfassen würde:

import Foundation 
import UserNotifications 

class NotificationCenterMock: UNUserNotificationCenter { 
    var request: UNNotificationRequest? = nil 
    override func add(_ request: UNNotificationRequest, withCompletionHandler completionHandler: ((Error?) -> Void)? = nil) { 
     self.request = request 
    } 
} 

jedoch UNUserNotificationCenter hat keine zugänglich initializers ich das Mock nicht instanziieren.

Ich bin nicht einmal sicher, ob ich testen kann, indem ich die Benachrichtigungsanfrage hinzufüge und die aktuellen Benachrichtigungen abrufe, da die Tests eine Berechtigung für den Simulator erfordern würden, die die Tests blockieren würde. Zurzeit habe ich die Benachrichtigungslogik in einen Wrapper umgestaltet, sodass ich dies zumindest in meiner gesamten Anwendung nachahmen und manuell testen kann.

Habe ich bessere Optionen als manuelle Tests?

Antwort

7

Sie können ein Protokoll für die von Ihnen verwendeten Methoden erstellen und eine Erweiterung für UNUserNotificationCenter erstellen, um sie zu übernehmen. Dieses Protokoll würde als "Brücke" zwischen der ursprünglichen UNUserNotificationCenter-Implementierung und Ihrem Mock-Objekt fungieren, um seine Methodenimplementierungen zu ersetzen.

Hier ist ein Beispiel Code, den ich auf einem Spielplatz geschrieben, und funktioniert gut:

/* UNUserNotificationCenterProtocol.swift */ 

// This protocol allows you to use UNUserNotificationCenter, and replace the implementation of its 
// methods in you test classes. 
protocol UNUserNotificationCenterProtocol: class { 
    // Declare only the methods that you'll be using. 
    func add(_ request: UNNotificationRequest, 
      withCompletionHandler completionHandler: ((Error?) -> Void)?) 
} 

// The mock class that you'll be using for your test classes. Replace the method contents with your mock 
// objects. 
class MockNotificationCenter: UNUserNotificationCenterProtocol { 
    func add(_ request: UNNotificationRequest, 
      withCompletionHandler completionHandler: ((Error?) -> Void)?) { 
    // Do anything you want here for your tests 
    print("Mock center log") 
    completionHandler?(nil) 
    } 
} 

// Must extend UNUserNotificationCenter to conform to this protocol in order to use it in your class. 
extension UNUserNotificationCenter: UNUserNotificationCenterProtocol { 
// I'm only adding this implementation to show a log message in this example. In order to use the original implementation, don't add it here. 
    func add(_ request: UNNotificationRequest, withCompletionHandler completionHandler: ((Error?) -> Void)?) { 
    print("Notification center log") 
    completionHandler?(nil) 
    } 
} 

/* ExampleClass.swift */ 

class ExampleClass { 

    // Even though the type is UNUserNotificationCenterProtocol, it will take UNUserNotificationCenter type 
    // because of the extension above. 
    var notificationCenter: UNUserNotificationCenterProtocol = UNUserNotificationCenter.current() 

    func doSomething() { 
    // Create a request. 
    let content = UNNotificationContent() 
    let request = UNNotificationRequest(identifier: "Request", 
              content: content, 
              trigger: nil) 
    notificationCenter.add(request) { (error: Error?) in 
     // completion handler code 
    } 
    } 
} 

let exampleClass = ExampleClass() 
exampleClass.doSomething() // This should log "Notification center log" 

/* TestClass.Swift (unit test class) */ 

class TestClass { 

    // Create your mock class. 
    var notificationCenter: UNUserNotificationCenterProtocol = MockNotificationCenter() 

    func doSomething() { 
    // Create a mock Request. 
    let fakeContent = UNNotificationContent() 
    let mockRquest = UNNotificationRequest(identifier: "mock", 
              content: fakeContent, 
              trigger: nil) 
    notificationCenter.add(mockRquest) { (error: Error?) in 
     // completion handler code 
    } 
    } 
} 

let testClass = TestClass() 
testClass.doSomething() // This should log "Mock center log" 

Denken Sie daran, dass jedes Mal, wenn Sie eine neue Methode verwenden, werden Sie es das Protokoll hinzufügen müssen, oder die Compiler wird sich beschweren.

Hoffe, das hilft!

+0

Scheint wie eine kluge Lösung, danke! – squarefrog

+0

Dies ist eine großartige Antwort. Denkst du, es ist möglich, einen ähnlichen Ansatz zu verfolgen, um 'func getNotificationSettings (completionHandler: @escaping (UNNotificationSettings) -> Swift.Void)' '? Ich habe Probleme, das zurückgegebene 'UNNotificationSettings'-Objekt zu verspotten, da es nicht instanziiert werden kann. – JimmyB

Verwandte Themen