Introducción: ¿Por qué probar aplicaciones Swift?
El desarrollo de una aplicación iOS o macOS de calidad es imposible sin pruebas adecuadas. En el ecosistema Swift, existe un potente framework XCTest que permite escribir los tres niveles de pruebas: unitarias (unit), de integración (integration) y de extremo a extremo (E2E). Cada uno de estos niveles es responsable de su propia área y ayuda a detectar errores en diferentes etapas del desarrollo.
En este artículo, analizaremos cómo configurar y escribir correctamente pruebas para aplicaciones Swift, utilizando prácticas y herramientas modernas. Aprenderás en qué se diferencian los distintos tipos de pruebas y obtendrás ejemplos de código listos para usar que puedes aplicar inmediatamente en tu proyecto.
Pruebas unitarias en Swift
Las pruebas unitarias son la base de la pirámide de pruebas. Verifican el funcionamiento de componentes individuales (métodos, clases, estructuras) de forma aislada de las dependencias externas.
Configuración de pruebas unitarias en Xcode
Para crear un target de prueba en Xcode, al crear un proyecto basta con marcar la casilla "Include Tests". Si el proyecto ya existe, añade un nuevo target: File → New → Target → iOS Unit Testing Bundle.
Ejemplo básico de prueba unitaria
Veamos un ejemplo simple de prueba de una calculadora:
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 debe ser igual a 8") } func testDivisionByZero() { XCTAssertThrowsError(try calculator.divide(10, 0)) { error in XCTAssertEqual(error as? CalculatorError, CalculatorError.divisionByZero) } }}Mejores prácticas para pruebas unitarias
- Aislamiento: Cada prueba debe ser independiente. Usa
setUpWithErrorytearDownWithErrorpara la preparación y limpieza. - Patrón AAA: Arrange (preparación), Act (acción), Assert (verificación).
- Una verificación por prueba: La prueba ideal verifica solo un comportamiento.
- Nomenclatura: Usa nombres descriptivos:
testMethodName_WhenCondition_ExpectedResult.
Pruebas de integración en Swift
Las pruebas de integración verifican la interacción entre componentes: trabajo con bases de datos, solicitudes de red, sistema de archivos. A diferencia de las pruebas unitarias, aquí no simulamos todo, sino que probamos interacciones reales.
Pruebas de Core Data
Ejemplo de prueba de trabajo con Core Data:
import XCTest@testable import MyApp
final class CoreDataIntegrationTests: XCTestCase { var coreDataStack: CoreDataStack! override func setUpWithError() throws { coreDataStack = CoreDataStack(inMemory: true) // Usamos almacenamiento en memoria } func testSaveAndFetchUser() { // Arrange let user = User(context: coreDataStack.viewContext) user.name = "Iván" 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, "Iván") }}Pruebas de la capa de red
Para las pruebas de integración de red, usa