Introducción a Swift Testing
Libranner Santos
10 julio, 20245min de lectura
Es necesario utilizar Xcode 16 Beta o superior para trabajar con Swift Testing.
En WWDC 2024, Apple introdujo un nuevo framework de código abierto para escribir pruebas en código Swift, Swift Testing. Está diseñado para ser fácil de usar y flexible. Nos provee una alternativa a XCTest
para poder escribir código más legible gracias al uso de diferentes macros y organizar nuestras pruebas eficientemente.
Características de Swift Testing
- Además de todas las plataformas Apple, soporta Linux y Windows, utilizando el mismo código.
- Es de código abierto.
- En Xcode 16 es la opción por defecto, aunque para pruebas de UI todavía necesitamos XCTest.
- Integrado en Swift Package Manager, Xcode 16 y Visual Studio Code (con la extensión Swift).
- Xcode Cloud soporta Swift Testing.
- Ejecuta las pruebas en paralelo y en orden aleatorio, por defecto.
Anatomía de una prueba
En el siguiente gráfico podemos visualizar las partes fundamentales de una prueba unitaria escrita con Swift Testing:
En este código:
- Usando
require
indicamos la condición que se tiene que cumplir para poder continuar, nota como debemos usartry
porque de no ser cumplida la condición la prueba fallará. En este caso, lo usamos para requerir que el constructor no retornenil
. Así como usábamosXCTUnwrap
enXCTest
. - Usamos el expression macro
expect
para evaluar la condición, en este caso, quemodel.items.count
sea mayor de1
. A diferencia deXCTest
que provee una serie de funciones comoXCTAssertEqual
,XCTAssertTrue
yXCTAssertGreaterThan
, con Swift Testing solo necesitamos hacer uso deexpect
.
Traits
Son características que podemos agregar a nuestros tests. Como por ejemplo:
- Agregar textos descriptivos.
- Controlar dónde se ejecuta el test.
- Modificar el comportamiento del test.
Veamos un ejemplo:
@Test(.enabled(if: ModelService.enabled))func hasMultipleItems() async throws {let model = try #require(Model())await model.fill()#expect(model.items.count > 1)}
En la macro @Test
asignamos un trait
(o característica) a la prueba que indica que solo estará habilitada cuando ModelService.enabled
sea verdadero.
A continuación el listado de los traits disponibles en Swift Testing:
Trait | Descripción |
---|---|
@Test(“Texto descriptivo”) | Personaliza el nombre de la prueba unitaria. |
@Test(.bug(“jira.com/issues/123“, “Título”)) | Referencia un ticket de Jira. |
@Test(.tags(.critical)) | Agrega tags. |
@Test(.enabled(if: Configuration.enableAll)) | Específica una condición en tiempo de ejecución. |
@Test(.disabled (“Flaky test”)) | Deshabilita una prueba unitaria. |
@Test(...) @available(macOS 15, *) | Deshabilita la prueba para un sistema operativo específico. |
@Test(.timeLimit(.minutes(3))) | Establece un tiempo límite. |
@Suite(.serialized) | Ejecuta los test uno a la vez, sin paralelización. |
@Suite
se utiliza para agrupar múltiples pruebas bajo un mismo grupo, lo veremos más detallado en un artículo futuro.
Swift Testing vs XCTest
Cómo se compara Swift Testing con respecto a su predecesor XCTest. A continuación algunas tablas demostrativas de las diferencias entre ambos.
XCTest | Swift Testing | |
---|---|---|
Cómo declaramos una prueba | Nombre debe empezar con “test” | Usando @Test |
Soporta categorías (traits) | No | Sí |
Ejecución en paralelo | Usando múltiples procesadores Solo en MacOS y simulador | In-process (usando Swift Concurrency). Soporta dispositivos reales. |
Cómo declaramos un grupo de pruebas | Heredando de XCTestCase | Usando @Suite |
Tipos que soporta | class | struct actor class |
Cómo ejecutar código antes de cada prueba | setUp() setUpWithError() async throws setUp() async throws | init() async throws |
Cómo ejecutar código después de cada prueba | tearDown() tearDownWithError() async throws tearDown() async throws | deinit() |
Crear sub-grupos | N/A | Puedes anidar Suites |
Integraciones con Xcode
Swift Testing no solo es la opción por defecto cuando creemos un nuevo proyecto en Xcode:
Sino que viene integrado en este entorno de desarrollo completamente, permitiéndonos, entre otras cosas, obtener más información cuando nuestras pruebas fallen:
También podemos usar el test snippet para crear rápidamente una prueba vacía. Solo tenemos que escribir la palabra “test” en Xcode y seleccionar del siguiente menú de contexto la opción que haga más sentido:
El resultado sería algo así:
@Test("<#display name#>")func <#name#>() async throws {<#body#>}
Estas son solo algunas de las integraciones. En próximos artículos, veremos aún más, como por ejemplo, la posibilidad de crear Test Plans basados en tags que agrupan una serie de pruebas.
Migrando a Swift Testing
Seguro que estás pensando en comenzar a usar Swift Testing lo más pronto posible. Aquí algunas cosas a tomar en cuenta:
- Podemos usar
XCTest
y Swift Testing en un mismo test target. Esto nos permite migrar a Swift Testing de manera escalonada. - Para clases
XCTest
con un solo método, se recomienda usar una función@Test
global. - Recuerda que ya no es necesario nombrar los funciones comenzando con "test", gracias a la macro
@Test
. - Seguiremos utilizado
XCTest
para pruebas de UI (XCUIApplication
), rendimiento (XCTMetric
), código escrito en Objective-C. - No uses
XCTAssert
en Swift Testing ni las nuevas macros (#expect
,#require
) cuando escribes pruebas conXCTest
.
Conclusión
Sin duda, Swift Testing es un paso más para hacer de Swift un lenguaje más universal y expresivo. Nos permite sentirnos cómodos escribiendo código para varios sistemas operativos y plataformas. Sin embargo, este artículo solo toca una pequeña parte de todo lo que trae consigo Swift Testing.
Seguiremos publicando más contenido sobre Swift Testing en las próximas semanas y compartiéndolo en nuestro blog y redes.