Pruebas en Swift: Unit, Integration, E2E — guía completa

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Pruebas en Swift: Unit, Integration, E2E — de la teoría a la práctica



Las pruebas de calidad no son solo una "buena práctica" en el desarrollo para iOS y macOS, sino una etapa críticamente importante que garantiza la estabilidad, seguridad y previsibilidad de la aplicación. En este artículo analizaremos tres niveles de pruebas en Swift: Pruebas Unitarias, Pruebas de Integración y E2E (end-to-end). Aprenderás en qué se diferencian, cuándo aplicarlas y cómo escribir pruebas efectivas utilizando los frameworks XCTest y XCUITest.



1. Pruebas Unitarias: verificamos los "bloques" de la aplicación



Las pruebas unitarias son el tipo de prueba más bajo nivel y más rápido. Verifican el funcionamiento de funciones individuales, métodos o clases (unidades) de forma aislada de las dependencias externas (red, base de datos, UI).



Principios básicos de las Pruebas Unitarias en Swift:

  • Aislamiento: el código bajo prueba no debe depender del estado de otros módulos.
  • Repetibilidad: la prueba debe dar el mismo resultado en cada ejecución.
  • Rapidez: miles de pruebas unitarias deben ejecutarse en segundos.


Ejemplo de Prueba Unitaria con XCTest:

import XCTest

class Calculator { func add(_ a: Int, _ b: Int) -> Int { return a + b } func divide(_ a: Int, _ b: Int) throws -> Int { guard b != 0 else { throw CalculationError.divisionByZero } return a / b }}

enum CalculationError: Error { case divisionByZero}

class CalculatorTests: XCTestCase { var calculator: Calculator! override func setUp() { super.setUp() calculator = Calculator() } override func tearDown() { calculator = nil super.tearDown() } func testAddition() { // Given let a = 5 let b = 3 // When let result = calculator.add(a, b) // Then XCTAssertEqual(result, 8, "5 + 3 debería ser igual a 8") } func testDivisionByZeroThrowsError() { // Usamos XCTAssertThrowsError para verificar excepciones XCTAssertThrowsError(try calculator.divide(10, 0)) { error in XCTAssertEqual(error as? CalculationError, .divisionByZero) } }}


Mejores prácticas para Pruebas Unitarias:

  • Usa el patrón AAA (Arrange-Act-Assert) — preparación, acción, verificación.
  • Nombra las pruebas de forma significativa: testMethodName_condition_expectedResult.
  • Evita probar métodos privados — prueba la interfaz pública.
  • Para mocks y stubs, usa protocolos e inyección de dependencias.


2. Pruebas de Integración: verificamos la interacción de componentes



Las pruebas de integración verifican cómo funcionan juntos los diferentes módulos de la aplicación. En el contexto de iOS, esto puede ser la interacción de la ViewModel con la red, Core Data o UserDefaults.



Ejemplo de Prueba de Integración con un mock de la capa de red:

import XCTest

// Protocolo para el servicio de red (permite sustituirlo fácilmente)protocol NetworkServiceProtocol { func fetchUser(id: Int, completion: @escaping (Result<User, Error>) -> Void)}

// Servicio real (no lo probamos en la prueba de integración)class RealNetworkService: NetworkServiceProtocol { func fetchUser(id: Int, completion: @escaping (Result<User, Error>) -> Void) { // Solicitud HTTP real }}

// Mock-servicio para pruebasclass MockNetworkService: NetworkServiceProtocol { var shouldReturnError = false var mockUser = User(id: 1, name: "Test User") func fetchUser(id: Int, completion: @escaping (Result<User, Error>) -> Void) { if shouldReturnError { completion(.failure(NSError(domain: "test", code: 500)))

Blogs

Book Recommendations