Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI - Mocking @EnvironmentObject data in preview

I have this code:

struct WelcomeView: View {
    @EnvironmentObject var userService: UserService
    var body: some View {
        Text(userService.user.username)
    }
}

struct WelcomeView_Previews: PreviewProvider {
    static var previews: some View {
        WelcomeView().environmentObject(UserService())
    }
}

What I want to achieve that all my UI components use mock data. I need to tell somehow that in preview I would like to see Text(userService.user.username) as Text("Alex") for example. How can I make it work? Where I need to initialise my user.username and where to put this mock. I just want to use the user object for all my views. I just skipped them for this example.

like image 408
Matrosov Oleksandr Avatar asked Dec 18 '22 13:12

Matrosov Oleksandr


2 Answers

Assuming the UserService has correctly designed using dependency injection, it can be used the following approach with any explicit changes in production code

struct WelcomeView_Previews: PreviewProvider {
    static var previews: some View {
        let userService = UserService()
        userService.user = User(username: "Alex", email: "[email protected]") // << any predefined set up here
        // any more parameters set up here

        return WelcomeView().environmentObject(userService)
    }
}
like image 106
Asperi Avatar answered Jan 08 '23 10:01

Asperi


You can either insert the mock data at the service level or at the view level. Since you'll be using this in multiple views, I'd recommend adding the mock capability to the service (as in the first example below).

I don't know what your UserService looks like so I've added a basic implementation to these examples.

Service level

import SwiftUI

struct User {
    var username: String
}

class UserService: ObservableObject {
    @Published var user: User = User(username: "Initial username")

    // If a mock user is provided to the UserService it will replace the initial user.
    init(mockUser: User? = nil) {
        if let user = mockUser {
            self.user = user
        }
    }
}

struct WelcomeView: View {
    @EnvironmentObject var userService: UserService

    var body: some View {
        Text(userService.user.username)
    }
}

struct WelcomeView_Previews: PreviewProvider {
    static var previews: some View {
        WelcomeView()
            .environmentObject(UserService(mockUser: User(username: "Test username")))
    }
}

View level

import SwiftUI

struct User {
    var username: String
}

class UserService: ObservableObject {
    @Published var user: User = User(username: "Initial username")
}

struct WelcomeView: View {
    @EnvironmentObject var userService: UserService

    // Optional mock user. Will replace the user from UserService if provided.
    var mockUser: User? = nil

    var body: some View {
        Text((mockUser != nil) ? mockUser!.username : userService.user.username)
    }
}

struct WelcomeView_Previews: PreviewProvider {
    static var previews: some View {
        WelcomeView(mockUser: User(username: "Test username"))
            .environmentObject(UserService())
    }
}
like image 24
Wesley Avatar answered Jan 08 '23 10:01

Wesley