Search code examples
iosswiftlocalelocalnotificationunusernotificationcenter

How to Unit Test locale-specific local notifications


I have just added local notifications to my app. These notifications are supposed to fire only if the app Locale's regionCode (i.e. Locale.current.regionCode) is "US" or "CA". I am not interested in the locale's language.

I will also want to write the complementary test case, but once I know how to write one test case, the other will follow naturally.

Therefore, my question is: How can a Locale be injected into the test (see testSuccessfulNotificationDelivery())?

LocalNotificationTests.swift:

class LocalNotificationTests: XCTestCase {

    let notification1 = LocalNotification(toTriggerInSeconds: 5)
    let notification2 = LocalNotification(toTriggerInSeconds: 6)

    // This object manages LocalNotifications 
    // by building them into UNUserNotifications
    // and then scheduling them using UNUserNotificationCenter.
    let notificationManager = NotificationManager()

    func testSuccessfulNotificationDelivery() {

        // setup locale and use it for testing, somehow
        let 🇨🇦 = Locale(identifier: "en_CA")

        // The answer to my question would go here. 
        // (Inject Locale into the test, somehow?)

        notificationManager.schedule(notifications: [notification1, notification2], 
                                     withRegionCode: 🇨🇦.regionCode)

        let expectation = self.expectation(description: "notification delivery")

        var deliveredNotifications: [UNNotification]?

        UNUserNotificationCenter.current().getDeliveredNotifications {
            deliveredNotifications = $0
            expectation.fulfill()
        }

        waitForExpectations(timeout: 10, handler: nil)

        XCTAssertEqual(deliveredNotifications?.count, 2) 
    }
}

Assume default setup() and tearDown().


Solution

  • class LocalNotificationTests: XCTestCase {
    
    let notification1 = LocalNotification(toTriggerInSeconds: 5)
    let notification2 = LocalNotification(toTriggerInSeconds: 6)
    
    // This object manages LocalNotifications 
    // by building them into UNUserNotifications
    // and then scheduling them using UNUserNotificationCenter.
    let notificationManager = NotificationManager()
    
    func testSuccessfulCanadaNotificationDelivery() {
        let canadaLocale = Locale("en_CA")
        XCTAssertTrue(notificationDelivered(with: canadaLocale))
    }
    
    func testNotificationDeliveryFailure() {
        let notCanadaOrUs = Locale("ru_RU")
        XCTAssertFalse(notificationDelivered(with: notCanadaOrUs))
    }
    
    
    private func notificationDelivered(with locale: Locale) -> Bool {
    
        // The answer to my question would go here. 
        // (Inject Locale into the test, somehow?)
    
        notificationManager.schedule(notifications: [notification1, notification2], 
                                     withRegionCode: locale.regionCode)
    
        let expectation = self.expectation(description: "notification delivery")
    
        var deliveredNotifications: [UNNotification]?
    
        UNUserNotificationCenter.current().getDeliveredNotifications {
            deliveredNotifications = $0
            expectation.fulfill()
        }
    
        waitForExpectations(timeout: 10, handler: nil)
    
        return (deliveredNotifications?.count ?? 0) == 2
    }
    

    Can you do something like this?