Search code examples
swiftmvvmtddobservableobject

Unit testing an @ObservableObject in Swift Test Driven Development


I'm trying to learn how to use MVVM architecture with TDD to solve some of the problems with not being able to unit test Views in SwiftUI.

I have an Alarm struct which takes a date:

import Foundation

struct Alarm {
    var time: Date
}

And I have a basic

class AlarmPickerViewModel: ObservableObject {
    @Published var alarm: Alarm

    init(alarm: Alarm) {
        self.alarm = alarm
    }

}

I'm struggling to work out how to write a unit test that fails if the AlarmPickerViewModel isn't a subclass of ObservableObject and the alarm property isn't @Published.

I've looked at this question on the site but it doesn't seem to help me.

Any pointers on where I'm going wrong please?


Solution

  • You can create a test that won't even compile if alarm is not @Published by simply creating a subscription to that property, since you will only be able to subscribe to it if it is @Published.

    The ObservableObject conformance adds an objectWillChange Publisher to your object, so to test that, you simply need to subscribe to that Publisher. If AlarmPickerViewModel wasn't ObservableObject, the test won't even compile.

    func testAlarmPickerViewModel() {
        let alarmPickerViewModel = AlarmPickerViewModel(alarm: Alarm(time: .distantFuture))
    
        alarmPickerViewModel.$alarm.sink(receiveValue: { print("ViewModel.alarm updated, new value: \($0)") })
    
        alarmPickerViewModel.objectWillChange.sink(receiveValue: { print("ViewModel updated: \($0)")})
    }