How to write unit test for NSNotification

后端 未结 3 1409
野性不改
野性不改 2020-12-31 04:23

I am working in swift, I want to refresh a page so I am sending it using notification, I am posting a notification in one ViewController and adding observer in another and i

3条回答
  •  猫巷女王i
    2020-12-31 04:35

    The general solution is: Use dependency injection (DI) to make your components unit-testable. You can choose use a DI framework (I don't know if there is any good framework for Swift exists yet) or use native approach (i.e. pass object around)

    One possible approach for your problem is to wrap NSNotificationCenter to make it mockable/injectable.

    This is just a basic idea how you can decouple dependencies. Please don't just copy & paste the code below and expect it to work without understanding it.

    import Foundation
    
    protocol NotificationCenter {
        func postNotificationName(name: String, object: AnyObject?)
    
        // you can make it take the arguments as NSNotificationCenter.addObserver
        func addObserver(callback: AnyObject? -> Void)
    }
    
    class MyNotificationCenter : NotificationCenter {
        var _notificationCenter: NSNotificationCenter
    
        init(_ center: NSNotificationCenter) {
            _notificationCenter = center
        }
    
        func postNotificationName(name: String, object: AnyObject?) {
            // call NSNotificationCenter.postNotificationName
        }
    
        func addObserver(callback: AnyObject? -> Void) {
            // call NSNotificationCenter.addObserver
        }
    }
    
    class MockNotificationCenter : NotificationCenter {
        var postedNotifications: [(String, AnyObject?)] = []
        var observers: [AnyObject? -> Void] = []
    
        func postNotificationName(name: String, object: AnyObject?) {
            postedNotifications.append((name, object))
        }
    
        func addObserver(callback: AnyObject? -> Void) {
            observers.append(callback)
        }
    }
    
    class MyView {
        var notificationCenter: NotificationCenter
    
        init(notificationCenter: NotificationCenter) {
            self.notificationCenter = notificationCenter
        }
    
        func handleAction() {
            self.notificationCenter.postNotificationName("name", object: nil)
        }
    }
    
    class MyController {
        var notificationCenter: NotificationCenter
    
        init(notificationCenter: NotificationCenter) {
            self.notificationCenter = notificationCenter
        }
    
        func viewDidLoad() {
            self.notificationCenter.addObserver {
                println($0)
            }
        }
    }
    

    // production code
    // in AppDeletate.applicationDidFinishLaunching
    let notificationCenter = MyNotificationCenter(NSNotificationCenter.defaultCenter())
    
    // pass it to your root view controller
    let rootViewController = RootViewController(notificationCenter: notificationCenter)
    // or
    rootViewController.notificationCenter = notificationCenter
    
    // in controller viewDidLoad
    self.myView.notificationCenter = self.notificationCenter
    
    // when you need to create controller
    // pass notificationCenter to it
    let controller = MyController(notificationCenter: notificationCenter)
    
    // in unit test
    
    func testMyView() {
        let notificationCenter = MockNotificationCenter()
        let myView = MyView(notificationCenter: notificationCenter)
        // do something with myView, assert correct notification is posted
        // by checking notificationCenter.postedNotifications
    }
    
    func testMyController() {
        let notificationCenter = MockNotificationCenter()
        let myController = MyController(notificationCenter: notificationCenter)
        // assert notificationCenter.observers is not empty
        // call it and assert correct action is performed
    }
    

提交回复
热议问题