Einleitung: Warum sollte man Swift-Apps testen?
Die Entwicklung einer qualitativ hochwertigen iOS- oder macOS-App ist ohne gründliches Testen nicht möglich. Im Swift-Ökosystem gibt es das leistungsstarke Framework XCTest, mit dem Sie alle drei Testebenen schreiben können: Modultests (Unit), Integrationstests (Integration) und End-to-End-Tests (E2E). Jede dieser Ebenen hat ihren eigenen Verantwortungsbereich und hilft, Fehler in verschiedenen Entwicklungsphasen zu erkennen.
In diesem Artikel werden wir uns ansehen, wie man Tests für Swift-Apps mit modernen Praktiken und Tools richtig konfiguriert und schreibt. Sie erfahren, wie sich die verschiedenen Testtypen unterscheiden, und erhalten fertige Codebeispiele, die Sie sofort in Ihrem eigenen Projekt anwenden können.
Unit-Testing in Swift
Unit-Tests sind das Fundament der Testpyramide. Sie überprüfen die Arbeit einzelner Komponenten (Methoden, Klassen, Strukturen) isoliert von externen Abhängigkeiten.
Einrichtung von Unit-Tests in Xcode
Um ein Test-Target in Xcode zu erstellen, reicht es bei der Projekterstellung, das Häkchen "Include Tests" zu setzen. Wenn das Projekt bereits existiert, fügen Sie ein neues Target hinzu: File → New → Target → iOS Unit Testing Bundle.
Basisbeispiel eines Unit-Tests
Betrachten wir ein einfaches Beispiel zum Testen eines Taschenrechners:
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 sollte 8 ergeben") } func testDivisionByZero() { XCTAssertThrowsError(try calculator.divide(10, 0)) { error in XCTAssertEqual(error as? CalculatorError, CalculatorError.divisionByZero) } }}Bewährte Praktiken für Unit-Tests
- Isolation: Jeder Test sollte unabhängig sein. Verwenden Sie
setUpWithErrorundtearDownWithErrorzur Vorbereitung und Bereinigung. - AAA-Muster: Arrange (Vorbereitung), Act (Aktion), Assert (Überprüfung).
- Eine Überprüfung pro Test: Ein idealer Test überprüft nur ein einziges Verhalten.
- Benennung: Verwenden Sie beschreibende Namen:
testMethodName_WhenCondition_ExpectedResult.
Integrationstesting in Swift
Integrationstests überprüfen die Interaktion zwischen Komponenten: Arbeit mit der Datenbank, Netzwerkanfragen, Dateisystem. Im Gegensatz zu Unit-Tests mocken wir hier nicht alles, sondern testen reale Interaktionen.
Testen von Core Data
Beispiel für das Testen der Arbeit mit Core Data:
import XCTest@testable import MyApp
final class CoreDataIntegrationTests: XCTestCase { var coreDataStack: CoreDataStack! override func setUpWithError() throws { coreDataStack = CoreDataStack(inMemory: true) // Verwenden In-Memory-Speicher } func testSaveAndFetchUser() { // Arrange let user = User(context: coreDataStack.viewContext) user.name = "Ivan" 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, "Ivan") }}Testen der Netzwerkschicht
Für Integrationstests des Netzwerks verwenden Sie e