This simple test fails in my project. Similar code in my application also crashes.
- How do I debug the problem?
- What project settings are required. I have added SwiftData as a framework to test (and application) targets?
Thanks,
The problem is with: modelContext.insert(item)
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
import XCTest
import SwiftData
@Model
class FakeModel {
var name: String
init(name: String) { self.name = name }
}
@MainActor
final class FakeModelTests: XCTestCase {
var modelContext: ModelContext!
override func setUp() {
super.setUp()
do {
let container = try ModelContainer(for: FakeModel.self, configurations: ModelConfiguration(isStoredInMemoryOnly: true))
modelContext = container.mainContext
} catch {
XCTFail("Failed to create ModelContainer: \(error)")
modelContext = nil
}
}
func testSaveFetchDeleteFakeItem() {
guard let modelContext = modelContext else {
XCTFail("ModelContext must be initialized")
return
}
let item = FakeModel(name: "Test")
modelContext.insert(item)
let fetchDescriptor = FetchDescriptor<FakeModel>()
let items = try! modelContext.fetch(fetchDescriptor)
XCTAssertEqual(items.count, 1)
XCTAssertEqual(items.first?.name, "Test")
modelContext.delete(item)
let itemsAfterDelete = try! modelContext.fetch(fetchDescriptor)
XCTAssertEqual(itemsAfterDelete.count, 0)
}
}
Yeah, as @joadan said, when you grab the model context with container.mainContext, the context doesn't hold the model container, and so the container becomes invalid outside of the scope of the setUp method; when you create a context with ModelContext(container), the context holds the container, and so the container has the same lifecycle as the context. You can see this subtle difference by observing the value of the ModelContext._container (private) property in the Xcode debugger.
If you'd test your code with the main context, which is main-actor isolated, consider holding the model container instead:
@MainActor
final class FakeModelTests: XCTestCase {
var modelContainer: ModelContainer!
override func setUp() {
super.setUp()
do {
modelContainer = try ModelContainer(for: FakeModel.self, configurations: ModelConfiguration(isStoredInMemoryOnly: true))
} catch {
XCTFail("Failed to create ModelContainer: \(error)")
modelContainer = nil
}
}
func testSaveFetchDeleteFakeItem() {
guard let modelContext = modelContainer?.mainContext else {
XCTFail("ModelContext must be initialized")
return
}
let item = FakeModel(name: "Test")
modelContext.insert(item)
...
}
}
Best,
——
Ziqiao Chen
Worldwide Developer Relations.