Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • 第 10 章:测试 SwiftData 应用

第 10 章:测试 SwiftData 应用

UI 测试:模拟数据操作

为什么需要 UI 测试 SwiftData 应用?

UI 测试是验证用户界面与数据层交互的关键环节,尤其对于 SwiftData 应用:

  1. 确保数据变化能正确反映在 UI 上
  2. 验证用户操作(如滑动删除、表单提交)能正确持久化数据
  3. 检测数据加载状态下的 UI 表现(如空数据视图)

测试环境搭建

1. 使用内存存储

// 测试用例中配置内存存储
func setUp() {
    let config = ModelConfiguration(isStoredInMemoryOnly: true)
    let container = try! ModelContainer(for: TodoItem.self, configurations: config)
    let context = container.mainContext
}

2. 预填充测试数据

private func insertMockItems(count: Int) -> [TodoItem] {
    var items = [TodoItem]()
    for i in 1...count {
        let item = TodoItem(title: "Test Item \(i)")
        context.insert(item)
        items.append(item)
    }
    try! context.save()
    return items
}

核心测试场景

场景 1:列表数据绑定测试

func testListDisplaysItems() {
    // Given
    let testItems = insertMockItems(count: 3)
    
    // When
    let app = XCUIApplication()
    app.launch()
    
    // Then
    XCTAssertEqual(app.tables.cells.count, 3)
    XCTAssertTrue(app.staticTexts["Test Item 1"].exists)
}

场景 2:新增数据测试

func testAddNewItem() {
    // Given
    let app = XCUIApplication()
    app.launch()
    
    // When
    app.navigationBars["Items"].buttons["Add"].tap()
    app.textFields["Title"].tap()
    app.textFields["Title"].typeText("New Test Item")
    app.buttons["Save"].tap()
    
    // Then
    XCTAssertTrue(app.staticTexts["New Test Item"].exists)
    
    // 验证持久化
    let fetchRequest = FetchDescriptor<TodoItem>()
    let items = try! context.fetch(fetchRequest)
    XCTAssertEqual(items.last?.title, "New Test Item")
}

场景 3:删除操作测试

func testDeleteItem() {
    // Given
    _ = insertMockItems(count: 1)
    let app = XCUIApplication()
    app.launch()
    
    // When
    let cell = app.tables.cells.element(boundBy: 0)
    cell.swipeLeft()
    app.buttons["Delete"].tap()
    
    // Then
    XCTAssertEqual(app.tables.cells.count, 0)
    
    // 验证数据库
    let fetchRequest = FetchDescriptor<TodoItem>()
    let items = try! context.fetch(fetchRequest)
    XCTAssertTrue(items.isEmpty)
}

高级技巧

1. 测试排序与过滤

func testSortOrder() {
    // Given
    _ = insertMockItems(count: 3)
    
    // When
    let app = XCUIApplication()
    app.launch()
    app.segmentedControls["Sort"].buttons["By Date"].tap()
    
    // Then
    let firstCell = app.tables.cells.element(boundBy: 0)
    XCTAssertTrue(firstCell.staticTexts["Test Item 3"].exists)
}

2. 测试关系更新

func testCategoryAssignment() {
    // Given
    let category = Category(name: "Work")
    let item = TodoItem(title: "Meeting")
    context.insert(category)
    context.insert(item)
    
    // When
    let app = XCUIApplication()
    app.launch()
    app.tables.cells["Meeting"].tap()
    app.pickers["categoryPicker"].selectValue("Work")
    app.buttons["Save"].tap()
    
    // Then
    XCTAssertEqual(item.category?.name, "Work")
}

最佳实践

  1. 隔离测试数据:每个测试用例使用独立的 ModelContainer
  2. 清理资源:在 tearDown() 中重置上下文
override func tearDown() {
    try? context.delete(model: TodoItem.self)
    context = nil
    container = nil
}
  1. 组合测试:将 XCTest 与 SwiftUI 预览结合使用
  2. 性能考量:使用 measure 块测试大数据量下的 UI 响应

常见问题处理

// 处理异步更新
let expectation = XCTestExpectation(description: "Wait for UI update")
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    expectation.fulfill()
}
wait(for: [expectation], timeout: 2)

通过系统化的 UI 测试,可以确保 SwiftData 应用在真实用户操作场景下的稳定性和数据一致性。

Last Updated:: 5/30/25, 5:48 PM