引言:为什么要测试 Swift 应用程序?
开发高质量的 iOS 或 macOS 应用程序离不开合理的测试。在 Swift 生态系统中,有一个强大的框架 XCTest,它允许我们编写所有三个级别的测试:单元测试 (unit)、集成测试 (integration) 和 端到端测试 (E2E)。每个级别负责各自的职责范围,并有助于在开发的不同阶段发现错误。
在本文中,我们将探讨如何使用现代实践和工具正确配置和编写 Swift 应用程序的测试。您将了解不同类型测试之间的区别,并获得可以直接在项目中应用的现成代码示例。
Swift 中的单元测试
单元测试是测试金字塔的基础。它们检查各个组件(方法、类、结构体)在隔离外部依赖关系的情况下的工作情况。
在 Xcode 中配置单元测试
要在 Xcode 中创建测试目标,在创建项目时只需勾选“Include Tests”复选框。如果项目已存在,请添加一个新目标:File → New → Target → iOS Unit Testing Bundle。
单元测试的基本示例
让我们看一个测试计算器的简单示例:
import XCTest
final class CalculatorTests: XCTestCase { var calculator: Calculator! override func setUpWithError() throws { calculator = Calculator() } override func tearDownWithError() throws { calculator = nil } func testAddition() { // Given let a = 5 let b = 3 // When let result = calculator.add(a, b) // Then XCTAssertEqual(result, 8, "5 + 3 应该等于 8") } func testDivisionByZero() { XCTAssertThrowsError(try calculator.divide(10, 0)) { error in XCTAssertEqual(error as? CalculatorError, CalculatorError.divisionByZero) } }}单元测试的最佳实践
- 隔离性:每个测试应该是独立的。使用
setUpWithError和tearDownWithError进行准备和清理。 - AAA 模式:Arrange(准备),Act(执行),Assert(验证)。
- 每个测试一个断言:理想的测试只检查一个行为。
- 命名:使用描述性名称:
testMethodName_WhenCondition_ExpectedResult。
Swift 中的集成测试
集成测试检查组件之间的交互:与数据库、网络请求、文件系统的协作。与单元测试不同,这里我们不会模拟所有内容,而是测试真实的交互。
测试 Core Data
测试 Core Data 工作的示例:
import XCTest@testable import MyApp
final class CoreDataIntegrationTests: XCTestCase { var coreDataStack: CoreDataStack! override func setUpWithError() throws { coreDataStack = CoreDataStack(inMemory: true) // 使用内存存储 } func testSaveAndFetchUser() { // Arrange let user = User(context: coreDataStack.viewContext) user.name = "伊万" user.age = 30 // Act try? coreDataStack.viewContext.save() let fetchRequest: NSFetchRequest<User> = User.fetchRequest() let users = try? coreDataStack.viewContext.fetch(fetchRequest) // Assert XCTAssertEqual(users?.count, 1) XCTAssertEqual(users?.first?.name, "伊万") }}测试网络层
对于网络的集成测试,请使用 r