Hi,
I'm wondering if anyone has a suggestion as to how to access a ModelContainer in the Unit Testing class.
I tried making a class to only instantiate the model container once, but it seems that Xcode is running this class in two different contexts (and they don't communicate): once when the test launches and then again from inside the XCTestCase subclass. If I try to save, I get an error about the two containers not being the same or a ton of validation errors.
Appreciate any help to point me in the right direction.
import SwiftUI
import SwiftData
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(MyModelContainer.shared.container)
}
}
@MainActor
final class MyModelContainer {
private init() { }
@MainActor
static var shared = MyModelContainer()
var container: ModelContainer {
if let internalContainer {
return internalContainer
}
let schema = Schema([
MyModel.self
])
if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil {
// testing
internalContainer = previewContext(with: schema)
} else if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
// previewing
internalContainer = previewContext(with: schema)
} else {
// production
internalContainer = productionContext(with: schema)
}
return internalContainer!
}
private var internalContainer: ModelContainer?
private func previewContext(with schema: Schema) -> ModelContainer {
let modelConfiguration = ModelConfiguration(schema: schema,
isStoredInMemoryOnly: true)
do {
let previewData = fetchPreviewData()
let container = try ModelContainer(for: schema, configurations: [modelConfiguration])
let context = container.mainContext
context.insert(previewData)
try context.save()
print("Loaded preview Container \(Date.now)")
return container
} catch {
print("Could not create ModelContainer: \(error)")
fatalError("Could not create ModelContainer: \(error)")
}
}
func productionContext(with schema: Schema) -> ModelContainer {
let modelConfiguration = ModelConfiguration(schema: schema,
isStoredInMemoryOnly: false)
do {
print("Loaded FlashMeContainer")
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}
}
final class FlashMeTests: XCTestCase {
@MainActor func testImport() throws {
let data = NSDataAsset(name: "myCodableModelData")?.data
let myCodableModel = try oldData!.decode(as: MyCodableModel.self)
let myModel = myCodableModel.convertToSwiftData()
let context = MyModelContainer.shared.container.mainContext
context.insert(myModel)
try context.save(myModel)
}
}
Post
Replies
Boosts
Views
Activity
I'm working to implement an infinite scrolling view using @SectionedFetchRequest. I'm able to update Core Data to reflect the new sections and order-within-the-section. @SectionedFetchRequest is correctly fetching and organizing everything on launch, but it's not updating as I update Core Data. I am using a SQLite app to simulate the Core Data query, and I can see @SectionedFetchRequest isn't picking up on everything that's there. Any thoughts as to what might be going on?
extension CDArticle {
static func displayFetchRequest() -> NSFetchRequest<CDArticle> {
let request: NSFetchRequest<CDArticle> = fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \CDArticle.sectionFolder, ascending: true),
NSSortDescriptor(keyPath: \CDArticle.sectionOrder, ascending: true)]
request.predicate = [ICPredicate.fetched].andPredicate()
return request
}
}
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@ObservedObject var controller = ArticleController.shared
@SectionedFetchRequest(fetchRequest: CDArticle.displayFetchRequest(),
sectionIdentifier: \CDArticle.sectionFolder,
transaction: Transaction(animation: .spring()))
private var fetchedSections
@State var queue = DispatchQueue.global(qos: .userInitiated)
init() {
detach {
await FolderFetcher.shared.fectchNewSections()
}
}
var body: some View {
ScrollViewReader { scrollProxy in
List {
ForEach(fetchedSections) { section in
Section(header: Text(FolderFetcher.getSectionName(section.id ?? "Nil") ?? "Nil")) {
ForEach(section) { article in
ArticleView(article: article)
.setLocationReaderKey(id: article.googleID!)
.id(article.googleID)
.onAppear {
if let topArticleID = topMostArticle {
scrollProxy.scrollTo(topArticleID, anchor: .top)
}
}
}
}
}
}
}
}
}