'How to add test data to PreviewProvider

I am new to iOS/Swift and to the MVVM architecture and was wondering how to send in test data to the SwiftUI Preview. (Actual data is received from the ViewModel from an API call)

Test Data that I want to add in:

test data = [(name: "Test1", price: "18.00-21.00"), (name: "Test2", price: "8.00-11.00"), (name: "Test3", price: "10.00")]

My View:

struct TodayView: View {

    @ObservedObject var viewModel: ViewModel
    
    var body: some View {
        NavigationView {
            
            List(viewModel.results, id: \.self) { item in

                Text(item.name)
                    .font(.subheadline)
                Text(item.price ?? "NIL")
                    .font(.headline)

            }
            .listStyle(InsetGroupedListStyle())
            .navigationBarTitle(Text("\(viewModel.titleDate)"))

        }
    }
}
    
struct TodayView_Previews: PreviewProvider {
    
    static var previews: some View {
        // Add Test Data here? How to pass it into TodayView?
        TodayView(viewModel: ViewModel())
    }
}

My View Model( I am sending both the Date & Actual Data to the View):

class ViewModel: ObservableObject {
    
    // Title Date
    @Published var titleDate: String = ""
    
    let dateLong = Date()
    
    func createDate() -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = "E, MMM d"
        return formatter.string(from: Date())
    }
    
    init(){
        self.results = [Model.Calendar]()
        titleDate = self.createDate()
        loadData()
    }


    func loadData() {

       // API Call

    }
    
    // Actual Data received from API call
    @Published var results: [Model.Calendar]

    
}

My Model:

struct Model {
    
    struct Calendar: Codable, Hashable {
        var name: String
        var price: String
    }

}


Solution 1:[1]

You can try the following:

struct TodayView_Previews: PreviewProvider {
    static var previews: some View {
        let viewModel = ViewModel()
        viewModel.results = <your_test_data>
        return TodayView(viewModel: viewModel)
    }
}

Also, you may need to remove loadData() from init (in ViewModel), so your test data won't be overridden.

Solution 2:[2]

You can create public protocol called 'ViewModelProtocol', which will have basic functions and properties that your ViewModel needs, like for instance

var results: [Model.Calendar]

And inside of View, you can put type of ViewModel to be of that protocol.

Then, you can inject any object that conforms to that particular 'ViewModelProtocol', which allows you to create two different view models ViewModel and ViewModelMock accordingly, where both of them should be conformed to ViewModelProtocol.

In ViewModelMock you will add dummy data for your testing, while regular ViewModel will have to fetch the data from the Network.

public protocol ViewModelProtocol {
  var results: [Model.Calendar]
}
struct ViewModel: ViewModelProtocol {...}
struct ViewModelMock: ViewModelProtocol {...}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Yessen Yermukhanbet