2016-11-29 8 views
6

私のアプリでは、正しい形式で通知が追加されていると主張したいと思います。私は通常、依存性注入でこれを行うだろうが、新しいUNUserNotificationCenter APIをテストする方法は考えられない。ユニットテストのiOS 10通知

import Foundation 
import UserNotifications 

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

しかし、UNUserNotificationCenterは一切アクセス初期化子を持っていない私はモックをインスタンス化することはできません。

私は通知要求をキャプチャしますモックオブジェクトを作成し始めました。

私は、通知要求を追加して現在の通知を取得することでテストすることができないと確信しています。テストでは、テストをストールするシミュレータの許可を要求する必要があります。現在、私は通知ロジックをラッパーにリファクタリングしているので、少なくとも私のアプリケーション全体でそれを模擬して手動でテストすることができます。

手動テストよりも良い選択肢がありますか?

答えて

7

使用しているメソッドのプロトコルを作成し、それに準拠するようにUNUserNotificationCenterで拡張を行うことができます。 このプロトコルは、元のUNUserNotificationCenter実装とその実装方法を置き換えるモックオブジェクトの間の「ブリッジ」として機能します。

ここで私が遊び場で書いたコード例です、と正常に動作します:

/* 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" 

は、新しいメソッドを使用するたびに、あなたがプロトコルに追加する必要がありますことを心に留めておいてください、またはコンパイラは文句を言うでしょう。

希望すると便利です。

+0

スマートなソリューションのようですね、ありがとう! – squarefrog

+0

これは素晴らしい応答です。同様のアプローチで 'func getNotificationSettings(completionHandler:@escaping(UNNotificationSettings) - > Swift.Void)'を実行することは可能でしょうか?インスタンス化できないので、返された 'UNNotificationSettings'オブジェクトを嘲笑するのに問題があります。 – JimmyB

関連する問題