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.