protocol DataManagerProtocol {
func fetchItems(predicate: Predicate<Item>?) throws -> [Item]
func saveItem(_ item: Item) throws
func deleteItem(_ item: Item) throws
}
class SwiftDataManager: DataManagerProtocol {
private let context: ModelContext
init(context: ModelContext) {
self.context = context
}
func fetchItems(predicate: Predicate<Item>?) throws -> [Item] {
let descriptor = FetchDescriptor<Item>(predicate: predicate)
return try context.fetch(descriptor)
}
}
class DataManagerTests: XCTestCase {
private var testContainer: ModelContainer!
private var testContext: ModelContext!
override func setUp() {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
testContainer = try! ModelContainer(for: Item.self, configurations: config)
testContext = testContainer.mainContext
}
func testFetchEmptyItems() throws {
let manager = SwiftDataManager(context: testContext)
let items = try manager.fetchItems(predicate: nil)
XCTAssertTrue(items.isEmpty)
}
}
class MockDataManager: DataManagerProtocol {
var mockItems: [Item] = []
var lastSavedItem: Item?
func fetchItems(predicate: Predicate<Item>?) throws -> [Item] {
return mockItems
}
func saveItem(_ item: Item) throws {
lastSavedItem = item
}
}
class ViewModelTests: XCTestCase {
func testViewModelLoadsItems() {
let mockManager = MockDataManager()
mockManager.mockItems = [Item(name: "Test")]
let viewModel = MyViewModel(dataManager: mockManager)
viewModel.loadItems()
XCTAssertEqual(viewModel.items.count, 1)
}
}
func testPredicateFiltering() throws {
let manager = SwiftDataManager(context: testContext)
let item1 = Item(name: "Important", isCompleted: false)
let item2 = Item(name: "Trivial", isCompleted: true)
try manager.saveItem(item1)
try manager.saveItem(item2)
let predicate = #Predicate<Item> { $0.isCompleted == false }
let results = try manager.fetchItems(predicate: predicate)
XCTAssertEqual(results.count, 1)
XCTAssertEqual(results.first?.name, "Important")
}
func testAsyncOperations() async throws {
let manager = SwiftDataManager(context: testContext)
let newItem = Item(name: "Async Test")
try await Task.detached {
try manager.saveItem(newItem)
}.value
let items = try manager.fetchItems(predicate: nil)
XCTAssertEqual(items.count, 1)
}
func testSaveErrorHandling() {
let manager = SwiftDataManager(context: testContext)
let invalidItem = Item(name: "")
XCTAssertThrowsError(try manager.saveItem(invalidItem)) { error in
XCTAssertTrue(error is ValidationError)
}
}
- 分离业务逻辑与持久层:通过协议隔离SwiftData具体实现
- 控制测试范围:单元测试应聚焦业务逻辑,而非持久层实现细节
- 使用内存存储:
isStoredInMemoryOnly配置确保测试隔离性 - 预置测试数据:setUp方法中初始化标准测试数据集
- 验证上下文状态:测试后检查ModelContext的状态一致性
- 性能考量:大量测试数据时使用@MainActor避免UI线程阻塞