DEV Community

David Goyes
David Goyes

Posted on

Swift Testing #1: Migración de una Suite de pruebas de XCTest a Swift Testing

Para crear una "suite" de pruebas de XCTest se usa un código parecido al que muestro a continuación:

import XCTest
@testable import ProductionProject
//
class SomeXCTest_deprecated: XCTestCase {
    func testX() throws {
        // GIVEN 
        // ...

        // WHEN 
        // ...

        // THEN ...
        XCTAssert(A == B, "Expected \(A) but received \(B)")
    }
}
Enter fullscreen mode Exit fullscreen mode

Si quisiera hacer la conversión a Swift Testing, lo convertiría así, donde puedo destacar el uso de struct en lugar de class, y el hecho de que se usa la etiqueta @Test en lugar del prefijo test. Por otro lado, notar el uso del macro #expect en lugar de XCTAssert. #expect evalúa una condición booleana que se muestra en el reporte de pruebas y que no interrumpe la ejecución del código en caso de que no se cumpla.

import Testing
@testable import ProductionProject
// 
struct SomeTest {
    @Test
    func x() throws {
        // GIVEN 
        // ...
        // WHEN 
        // ...
        // THEN ...
        #expect(A == B, "Expected \(A) but received \(B)")
    }
}
Enter fullscreen mode Exit fullscreen mode

Swift Testing solo está disponible a partir de Xcode 16. Supuéstamente requiere Swift 6 (según la documentación), sin embargo, creé un proyecto con Swift 5 e igual puedo usar Swift Testing.

Nombramiento de una prueba

En Swift Testing, el nombre de la prueba puede venir dado por el nombre del método, o por una descripción dentro de la etiqueta @Test. También se puede nombrar el método con "backticks" en lugar de usar la descripción dentro de la etiqueta - Hay un error de compilación se se usan las dos técnicas simultáneamente para la misma prueba. Esto representa un salto significativo a nivel de legibilidad del reporte de pruebas, puesto que ahora se pueden usar espacios para separar palabras.

import Testing
@testable import ProductionProject
// 
struct SomeTest {
    @Test("GIVEN some conditions, WHEN executing something, THEN it should return X")
    func x() throws {
        // ...
    }
//
    func `GIVEN some conditions, WHEN executing something, THEN it should...`() throws {
        // ...
    }
//
    @Test
    func GIVENsomeconditionsWHENexecutingsomethingTHENitShouldReturnX() throws {
        // ...
    }
}
Enter fullscreen mode Exit fullscreen mode

Algunas características adicionales:

  • Se puede tener XCTest y Swift Testing de forma simultánea en el mismo archivo y proyecto.
  • No es necesario migrar todas las pruebas de XCTest a Swift Testing.
  • El framework prioriza "value-types" así que, si no se requiere el tearDown (que se implementa con deinit de una clase), hay que procurar usar struct.

En el video de Swift and Tips (citado en las referencias) se menciona que hay que importar el paquete (SPM) de swift-testing, aunque por experimentación puedo asegurar que Swift Testing ya viene integrado en Xcode.

Removiendo dependencia manual de Swift Testing vieja

El proyecto del video de Swift and Tips estaba incluyendo un paquete de Swift para Swift Testing (https://github.com/swiftlang/swift-testing/releases) cuya versión era 0.10.
Con esta versión traté de crear una prueba que fallara (#expect(1 == 2)), pero aunque en la consola aparecía fallida, en el reporte se mostraba como si pasara.
Por esta razón, eliminé la dependencia de SPM para Swift Testing, para trabajar directamente con la versión incluida en Xcode 26.
Para ello, fui a OnlineStoreMV > Project > Package Dependency y eliminé manualmente la dependencia.
Luego, al tratar de compilar las pruebas obtuve el siguiente error, cuando se importaba la biblioteca Testing:

"unable to find module dependency _TestingInternals"
Para solucionarlo, limpié el proyecto (Cmd+Shift+K) y volví a compilarlo.

Interoperabilidad entre XCTAssert y @test

Para que XCTAssertfuncione, requiere vivir en una clase de tipo XCTestCase para que sea ejecutada por un XCTestRun en un XCTestSuite. Por esta razón, si trato de usar un XCTAssert dentro de un método marcado con @Test de Swift Testing, no va a funcionar.

import XCTest
import Testing
struct MyTests {
  @Test
  func something() {
    XCTAssert(2 == 3) // ¡No funciona! La prueba pasa.
    #expect(2 == 3) // Aquí la prueba no pasa, que es lo correcto.
  }
}
Enter fullscreen mode Exit fullscreen mode

No obstante, si una prueba marcada con @Test no tiene ningún #expect sino solo XCTAssert, igual es reconocida por el runner de pruebas de Swift Testing.

Referencias bibliográficas

  • Video " Mastering Swift Testing: Installation & Refactoring from XCTest to @test Macro", aquí.
  • Lista de reproducción "Swift Testing" (Swift and Tips), aquí.
  • Documentación sobre Swift Testing, aquí.
  • Meet Swift Testing, WWDC 2024, aquí.
  • Go further with Swift Testing, WWDC 2024, aquí.
  • Repositorio de github de Swift Testing, aquí.
  • Artículo, "Is MVVM Necessary for Developing Apps with SwiftUI?", aquí.
  • Proyecto "OnlineStore made with SwiftUI (Vanilla) and Observation", aquí.

Top comments (0)