swiftunit-testingswift-testing

Swift testing NotificationCenter


In XCTest I can use expectation(forNotification:) for testing NSNotificationCenter post notifications like:

func testLoginNotification() {
        let notificationExpectation = expectation(forNotification: .login, object: nil,    handler: nil)

        methodPostNotificationLogin()

        wait(for: [notificationExpectation], timeout: 2)
}

How to do this in swift testing?

@Test fun loginNotification() {
   #expect()
}

Solution

  • You can directly wait for notifications in your test code.

    @Test("Login", .timeLimit(.minutes(1))) 
    func loginNotification() async {
        let asyncSequence = NotificationCenter.default.notifications(named: .login)
        let iterator = asyncSequence.makeAsyncIterator()
        _ = await iterator.next()
    }
    

    You don't need to #expect anything if you just want to detect the existence of a notification. As soon as the asyncSequence produces an element, next will return some non-nil Notification.

    If you need a shorter time limit, it is a bit more tricky. You can wrap the above in a Task, then start another Task that waits for a desired amount of time before cancelling the first task.

    var timedOut = false
    let mainTask = Task {
        let asyncSequence = NotificationCenter.default.notifications(named: .login)
        let iterator = asyncSequence.makeAsyncIterator()
        _ = await iterator.next()
    }
    let timeoutTask = Task.detached {
        try await Task.sleep(for: .seconds(10))
        timedOut = true
        mainTask.cancel()
    }
    _ = await mainTask.result
    if timedOut {
        Issue.record("timed out")
    }