You Don't Need MVVM to Test SwiftUI
protocol MovieLoader { func load() async throws -> [Movie] } struct MovieList: View { @State var movies = [Movie]() let loader: MovieLoader var body: some View { List(movies, rowContent: MovieRo...

Source: DEV Community
protocol MovieLoader { func load() async throws -> [Movie] } struct MovieList: View { @State var movies = [Movie]() let loader: MovieLoader var body: some View { List(movies, rowContent: MovieRow.init) .task { await load() } } func load() async { movies = (try? await loader.load()) ?? [] } } func test_load_loadsMovies() async { let expected = [anyMovie()] let stubbed = StubMovieLoader(stubs: expected) let sut = MovieList(loader: stubbed) await sut.load() XCTAssertEqual(sut.movies, expected) } If you try to run this test as-is, it will fail. Thehe reason is that @State in a SwiftUI view only connects to an in-memory store if the view has been mounted into a real view hierarchy. The most common workaround is to move the logic into an @Observable. @Observable class MovieListViewModel { var movies = [Movie]() let loader: MovieLoader init(loader: MovieLoader = RemoteMovieLoader()) { ... } func load() async { movies = (try? await loader.load()) ?? [] } } struct MovieList: View { @State va