-
Migra a Swift Testing
Descubre cómo incorporar sin miedo Swift Testing junto con tus XCTests gracias a la interoperabilidad entre frameworks de pruebas. Descubre las mejores prácticas y los patrones para implementar de forma gradual funcionalidades de pruebas avanzadas que aceleran el desarrollo y aumentan la cobertura.
Capítulos
- 0:07 - Introducción
- 1:08 - Aspectos básicos de Swift Testing
- 2:50 - Estrategia de migración
- 5:48 - Interoperabilidad del framework de pruebas
- 7:43 - Modos de interoperabilidad
- 13:02 - Patrones comunes de migración
- 15:34 - Pruebas parametrizadas
- 18:02 - Pruebas de salida
- 20:04 - Próximos pasos
Recursos
Videos relacionados
WWDC26
WWDC24
-
Buscar este video…
-
-
1:12 - Name a test using a raw identifier
import Testing @testable import DemoApp @Test func `Default climate: tropical`() async throws { let fruit = Fruit(name: "Coconut") #expect(fruit.climate == .tropical) } -
5:03 - Wrap XCTFail in a test helper function
func testUniqueFruitNames() async throws { assertUnique(Market.fruits + [Fruit.lychee]) } // TestHelpers.swift func assertUnique(_ fruits: [Fruit], file: StaticString = #filePath, line: UInt = #line) { var uniqueNames = Set<String>() for name in fruits.map(\.name) { if !uniqueNames.insert(name).inserted { XCTFail("Duplicate name: \(name)", file: file, line: line) } } } -
10:12 - Replace XCTFail with Issue.record in the test helper
import Testing func assertUnique(_ fruits: [Fruit], sourceLocation: SourceLocation = ...) { var uniqueNames = Set<String>() for name in fruits.map(\.name) { if !uniqueNames.insert(name).inserted { Issue.record("Duplicate name: \(name)", sourceLocation: sourceLocation) } } } -
12:15 - Run Swift Package tests with the strict interoperability mode from Terminal
> SWIFT_TESTING_XCTEST_INTEROP_MODE=strict swift test -
13:10 - Common migration: skipping tests
let isFall = false // XCTest func testSwallowFallMigration() async throws { try XCTSkipIf(!isFall, "Wrong season for migration") // ... } // Test.cancel interoperability from Swift Testing func testSwallowFallMigration() async throws { if !isFall { try Test.cancel("Wrong season for migration") } // ... } // ✅ Prefer test trait in Swift Testing @Test(.enabled(if: isFall, "Wrong season for migration")) func `Swallow fall migration`() async throws { // ... } -
13:41 - Common migration: halting after test failures
func testExample() async throws { #expect(Fruit.banana.climate == .temperate) try #require(Fruit.banana == Fruit.plantain) XCTFail("This is never reached") } -
15:57 - Example of nested loops which can be converted into a parameterized @Test function
struct BirdTests { @Test func `Birds flap wings successfully`() async throws { for bird in Aviary.birds { for count in (40...100) { try await bird.flapWings(count: count) } } } } -
16:47 - Refactor nested loops into a parameterized @Test function
struct BirdTests { @Test(arguments: Aviary.birds, 40...100) func `Birds flap wings successfully`(bird: Bird, count: Int) async throws { try await bird.flapWings(count: count) } } -
18:21 - Precondition check on empty input name in an initializer
// In `Bird.init(...)` if name.isEmpty { preconditionFailure("Bird name cannot be empty") } -
19:27 - Add coverage for precondition failure with exit test
extension BirdTests { @Test func `Bird with empty name crashes`() async throws { await #expect(processExitsWith: .failure) { _ = Bird(name: "") } } }
-