Unit testing SwiftData

Problem

Trying out SwiftData, I attempted to write unit tests for some models I was writing, but got a crash when testing appending to a collection.

Context

Here's a sample reminiscent of the set up I have:

// Foo.swift

import SwiftData

@Model
final class Foo {
    @Relationship(.cascade) private(set) var barCollection: [Bar] = [Bar]()
   
    ...

    func append(bar: Bar) {
      defer {
          // some logic here
      }

      barCollection.append(bar)
    }
}

// Bar.swift

import SwiftData

@Model 
final class Bar {
    var value: Int

   init(value: Int) {
       self.value = value
   }
}

In my test, I'm attempting to append to the Bar array, and ensure that my append(bar:) method is doing it's job:

// FooTests.swift

@testable import FooApp
import XCTest

final class FooTests: XCTestCase {
    func testAppendBar() {
        let foo = Foo(bar: [])

        foo.append(bar: Bar(value: 0))

        XCTAssertFalse(foo.barCollection.isEmpty)

        // Assertions for logic enclosed in `defer`
        . . .
    }
}

However, my test crashes on the assertion with EXC_BREAKPOINT, claiming issues with the getter for the array. Not much more info is given beyond that, except the stack trace showing that it crashed after attempting to assertion.

Testing with sample code

Using the project found here: https://developer.apple.com/documentation/coredata/adopting_swiftdata_for_a_core_data_app

I attempted to write unit tests for the Trip object attempting something similar with the BucketList array, and also seeing the same crash. Note: I did have to meddle with the project a bit to get it to compile since it wasn't compiling from the get go because of issues with the sample data.

Final question

Why am I not able to directly access the array holding persisted models and is there a way to test this properly?

My hunch is that since it's persisted, it's not a straightforward process anymore to retrieve the array, and if that's the case, I'm not sure why. Looking at the sample project linked above, the bucketList array is retrieved perfectly fine in the view it's being displayed in, so I know there's a lapse in my understanding of SwiftData and the appropriate setup for unit testing.

Software Used

Xcode 15.0 beta 2 • iOS 17 Simulator

Replies

In my unit tests, I need to insert Foo into a context before I can set the relationship to Bar. If the parent entity does not have a context I see a crash in the getter.

let foo = Foo(bar: [])
container.mainContext.insert(foo)

foo.append(bar: Bar(value: 0))

You will need to mark the test as running on the MainActor to access the mainContext.