The demo project to show how to organize code to make SwiftUI apps easy to be test
TestableApp
I combined the idea to use functional programming instead of an loader instance in ModelView(I prefer to think of it as a service) and Resolver.
Functional signatures for loads or actions
typealias AsyncAction<T> = (T) async throws -> Void
typealias Loading<T> = () async throws -> T
How to use it in the app
@main
struct TestableApp: App {
init() {
Resolver.register {
NewsService.initLoader()
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
How to use it in a view for running
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Resolver.register {
NewsService.mockLoader() //the app isn't running in canvas preview
// NewsService.initLoader() //the app is running in canvas preview
}
return ContentView()
}
}
How to use it in tests
class TestableAppTests: XCTestCase {
private var service: NewsService!
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
Resolver.register {
NewsService.mockLoader()
}
service = NewsService()
}
func testLoadingNews() async throws {
XCTAssertEqual(service.news.count, 0)
try await service.fetchAllNews()
XCTAssertGreaterThan(service.news.count, 0)
}
}