Unit Test vs Integration Test
La base de la estrategia de testing en iOS: ¿tests unitarios que aíslan la unidad o tests de integración que validan la interacción entre componentes? ¿Cómo construir correctamente la pirámide de testing?
La nueva biblioteca de pruebas de código abierto de Apple — basada en macros, integrada de forma nativa con Swift Concurrency
Un framework con ~13 años de historia y probado en producción — la única opción para pruebas de UI y de rendimiento
La tendencia es clara, pero una 'migración masiva' es un riesgo innecesario. Escribe las nuevas pruebas unitarias y de integración con Swift Testing: aporta menos código, captura automática de valores, pruebas parametrizadas integradas y paralelismo. Deja las pruebas de UI y de rendimiento en XCTest; la documentación de Apple lo pide así. Como ambos frameworks pueden convivir en el mismo target y Swift 6.4 introdujo el reporte cruzado, una migración masiva no es necesaria: avanza archivo por archivo.
| Categoría | Swift Testing | XCTest |
|---|---|---|
| Rendimiento | 8/10 | 8/10 |
| Facilidad de aprendizaje | 7/10 | 6/10 |
| Ecosistema | 6/10 | 8/10 |
| Comunidad | 6/10 | 8/10 |
| Mercado laboral | 5/10 | 7/10 |
| A prueba de futuro | 9/10 | 6/10 |
// Swift Testing — prueba unitaria async parametrizada
import Testing
@testable import PaymentKit
@Suite("Cálculo de precio")
struct PriceCalculatorTests {
@Test("El descuento se calcula correctamente con códigos de cupón válidos",
arguments: [
("SAVE10", 100.0, 90.0),
("SAVE20", 100.0, 80.0),
("NONE", 100.0, 100.0)
])
func discountIsApplied(code: String, base: Double, expected: Double) async throws {
let calculator = PriceCalculator()
let result = try await calculator.applyDiscount(code: code, to: base)
#expect(result == expected, "para \(code) se esperaba \(expected), llegó \(result)")
}
@Test("Un cupón inválido lanza un error")
func invalidCouponThrows() async throws {
let calculator = PriceCalculator()
await #expect(throws: CouponError.invalid) {
try await calculator.applyDiscount(code: "XXX", to: 100.0)
}
}
@Test("El total del carrito es obligatorio", .disabled("El servicio de carrito aún no se ha migrado"))
func cartTotalRequired() async throws {
let calculator = PriceCalculator()
try #require(calculator.cartTotal > 0)
}
}// XCTest — mismo escenario (cálculo de precio) + prueba de UI
import XCTest
@testable import PaymentKit
final class PriceCalculatorTests: XCTestCase {
var calculator: PriceCalculator!
override func setUpWithError() throws {
calculator = PriceCalculator()
}
func testDiscountIsAppliedForKnownCoupons() async throws {
let cases: [(String, Double, Double)] = [
("SAVE10", 100.0, 90.0),
("SAVE20", 100.0, 80.0),
("NONE", 100.0, 100.0)
]
for (code, base, expected) in cases {
let result = try await calculator.applyDiscount(code: code, to: base)
XCTAssertEqual(result, expected, "cupón: \(code)")
}
}
// XCTAssertThrowsError es síncrono; en una llamada async usa do/catch + XCTFail
func testInvalidCouponThrows() async throws {
do {
_ = try await calculator.applyDiscount(code: "XXX", to: 100.0)
XCTFail("se esperaba un error")
} catch {
XCTAssertEqual(error as? CouponError, .invalid)
}
}
}
// Prueba de UI — solo posible con XCTest/XCUITest
final class CheckoutUITests: XCTestCase {
func testApplyCouponButtonUpdatesTotal() throws {
let app = XCUIApplication()
app.launch()
app.textFields["couponField"].tap()
app.textFields["couponField"].typeText("SAVE10")
app.buttons["applyCouponButton"].tap()
XCTAssertEqual(app.staticTexts["totalLabel"].label, "$90.00")
}
}La tendencia es clara, pero una 'migración masiva' es un riesgo innecesario. Escribe las nuevas pruebas unitarias y de integración con Swift Testing: aporta menos código, captura automática de valores, pruebas parametrizadas integradas y paralelismo. Deja las pruebas de UI y de rendimiento en XCTest; la documentación de Apple lo pide así. Como ambos frameworks pueden convivir en el mismo target y Swift 6.4 introdujo el reporte cruzado, una migración masiva no es necesaria: avanza archivo por archivo.
Solicita una consultoría gratuitaNo. Swift Testing es la opción por defecto recomendada por Apple para las nuevas pruebas unitarias y de integración, pero XCTest no se ha eliminado; XCUITest (automatización de UI) y XCTMetric (pruebas de rendimiento) siguen existiendo solo en XCTest. Ambos pueden trabajar juntos gracias al reporte cruzado entre frameworks introducido con Swift 6.4.