Search code examples
swiftasynchronoustimetimer

Unit Testing a Timer?


I want to test that a signal is getting fired every 6 seconds. My code looks like this:

class DataStore {

    var clinics: Int { return clinicsSignal.lastDataFired ?? 0 }    
    let clinicsSignal = Signal<Int>(retainLastData: true)
    var timer: Timer?

    init() {
    }

    func load() {

        self.clinicsSignal.fire(0)

        DispatchQueue.main.async { [weak self] in
            self!.timer?.invalidate()
            self!.timer = Timer.scheduledTimer(withTimeInterval: 6.0, repeats: true) { [weak self] _ in
                self?.clinicsSignal.fire(9)
            }
        }
    }
}

My test code looks like this:

func testRefresh() {

    var dataStore: DataStore = DataStore()

    dataStore.clinicsSignal.subscribeOnce(with: self) {
        print("clinics signal = \($0)")
        dataStore.clinicsSignal.fire(0)
    }

    dataStore.load()

    sleep(30)

    print("clinics3 = \(dataStore.clinics)")

}

When I sleep for 30 seconds, the timer code doesn't get ran again until after the 30 seconds, therefore it's not getting ran once every 6 seconds like it's supposed to. Any idea on how to test that code in a timer is gettin hit at specific times? Thanks.


Solution

  • The sleep function blocks your thread and timers are associated to threads. You should use expectation.

    func testRefresh() {
    
        var dataStore: DataStore = DataStore()
        let expec = expectation(description: "Timer expectation") // create an expectation
        dataStore.clinicsSignal.subscribeOnce(with: self) {
            print("clinics signal = \($0)")
            dataStore.clinicsSignal.fire(0)
            expec.fulfill() // tell the expectation that everything's done
        }
    
        dataStore.load()
        wait(for: [expec], timeout: 7.0) // wait for fulfilling every expectation (in this case only one), timeout must be greater than the timer interval
    }