Search code examples
swiftuicombine

Mocking view model in swiftui with combine


Is there a way to mock the viewmodels of an application that uses SwiftUI and Combine? I always find articles about mocking services used by the viewmodel but never mocking a viewmodel itself.

I tried to create protocols for each viewmodel. Problem: the @Published wrapper cannot be used in protocols. It seems like there are no solutions...

Thanks for your help


Solution

  • Using a protocol type as @ObservableObject or @StateObject would not work. Inheritance might be a solution (like Jake suggested), or you could go with a generic solution.

    protocol ContentViewModel: ObservableObject {
        var message: String { get set }
    }
    

    Your view model would be simple.

    final class MyViewModel: ContentViewModel {
        
        @Published var message: String
        init(_ message: String = "MyViewModel") {
            self.message = message
        }
    }
    

    On the other hand, your views would be more complex using a constrained generic.

    struct ContentView<Model>: View where Model: ContentViewModel {
        @ObservedObject
        var viewModel: Model
        
        var body: some View {
            VStack {
                Text(viewModel.message)
                Button("Change message") {
                    viewModel.message = "🥳"
                }
            }
        }
    }
    

    The disadvantage is that you have to define the generic concrete type when using the view --- inheritance could avoid that.

    // your mock implementation for testing
    final class MockViewModel: ContentViewModel {
        @Published var message: String = "Mock View Model"
    }
    
    let sut = ContentView<MockViewModel>(viewModel: MockViewModel())