Para que Xcode resalte el test que llamó a un helper compartido de XCTest, asigna al helper los parámetros predeterminados #filePath y #line y pasa ambos a sus aserciones. Esta guía muestra la solución, los helpers anidados y el equivalente de Swift Testing.

¿Por qué Xcode resalta el helper?

Una aserción compartida introduce otra ubicación en el código fuente. El test llama a tu helper, y el helper llama a una aserción de XCTest. Si esa aserción usa sus argumentos de ubicación predeterminados, la ubicación informada será la de la aserción dentro del helper. Apple documenta file: StaticString = #filePath y line: UInt = #line tanto en XCTAssertEqual como en XCTFail.

Captura la ubicación del llamador en el límite del helper y luego pasa esos valores. Los valores predeterminados de ubicación del código fuente de Swift capturan el punto de llamada; el proyecto Swift explica este comportamiento en SE-0274: Nombres concisos de archivos mágicos. Apple también muestra este patrón exacto de helper de XCTest en Migrar a Swift Testing, donde Xcode atribuye el error a la llamada al helper.

Para quien desarrolla en Xcode en una Mac, la tarea concreta consiste en conservar las comprobaciones reutilizables y hacer que cada error remita a la entrada de test pertinente. Los ejemplos siguientes usan únicamente arrays de enteros pequeños. No requieren un modelo de la app, un sustituto de servicio, una dependencia descargada ni acceso a la red para ejecutarse.

Añadir parámetros de ubicación del llamador a un helper de XCTest

Usa un destino de tests unitarios de macOS existente. Si el proyecto necesita uno, elige File > New > Target, filtra por Test y selecciona Unit Testing Bundle. Para añadir un archivo de test, elige File > New > New File From Template y selecciona XCTest Unit Test. Estas son las rutas documentadas por Apple en Añadir tests al proyecto de Xcode.

Coloca este archivo de test completo en ese destino de tests unitarios. El segundo test proporciona intencionadamente un total esperado incorrecto para que puedas inspeccionar la ubicación del error.

import XCTest

private func assertTotal(
    _ values: [Int],
    equals expected: Int,
    file: StaticString = #filePath,
    line: UInt = #line
) {
    let actual = values.reduce(0, +)
    XCTAssertEqual(
        actual,
        expected,
        "Unexpected total for \(values)",
        file: file,
        line: line
    )
}

final class TotalHelperTests: XCTestCase {
    func testMatchingTotal() {
        assertTotal([2, 3, 4], equals: 9)
    }

    func testDeliberatelyIncorrectTotal() {
        assertTotal([2, 3, 4], equals: 10)
    }
}

Las partes importantes son los tipos de parámetros, los valores predeterminados y el paso explícito de los valores. StaticString y UInt coinciden con la firma de la aserción de XCTest. Mantén #filePath y #line directamente en los valores predeterminados del helper. Así, el test llama al helper sin proporcionar manualmente ninguno de los argumentos de ubicación. Consulta los parámetros de XCTAssertEqual documentados.

La aritmética es ilustrativa: 2 + 3 + 4 es 9, así que la primera comparación coincide y la segunda no. Estos casos aritméticos se comprobaron localmente con Python. En el entorno de investigación no había un ejecutable de Swift disponible, así que se inspeccionaron los ejemplos de Swift, pero no se compilaron ni ejecutaron aquí.

Verificar la ubicación y el resultado del test

Elige Product > Test o ejecuta el test individual con el control de reproducción situado junto a su declaración. Después, selecciona el test que falla en el Test navigator e inspecciona el diagnóstico. Apple describe estos controles y los detalles del error en Ejecutar tests e interpretar resultados.

En este ejemplo, verifica dos resultados distintos: testDeliberatelyIncorrectTotal() falla y el diagnóstico de su aserción apunta a la llamada assertTotal([2, 3, 4], equals: 10). La atribución al llamador esperada sigue el patrón de paso de ubicación que muestra Apple. Después de comprobarlo, cambia 10 a 9 y vuelve a ejecutar los tests; elimina la discrepancia intencional de la suite de tests definitiva.

Si el diagnóstico sigue apuntando dentro del helper, inspecciona la llamada a la aserción final. Declarar parámetros de ubicación no basta si el helper omite file: file o line: line en el punto donde se registra el error.

Conservar la ubicación en cada nivel de helpers

Los helpers anidados necesitan el mismo paso explícito de los valores. Supongamos que un test llama a un helper de dominio, que a su vez llama a un helper de aserción de nivel inferior. Si el helper externo omite los argumentos de ubicación, el helper de nivel inferior capturará ese punto de llamada intermedio.

Este es un límite del lenguaje que conviene comprobar: los valores predeterminados de ubicación del código fuente no se transmiten automáticamente a través de llamadas arbitrarias a helpers. SE-0285: Facilitar la transición a cadenas mágicas concisas para archivos explica explícitamente que estos valores predeterminados no son transitivos.

El siguiente es un archivo de test alternativo completo. Muestra cómo un helper llama a otro y conserva la ubicación del test original.

import XCTest

private func assertIntegerEqual(
    _ actual: Int,
    _ expected: Int,
    file: StaticString = #filePath,
    line: UInt = #line
) {
    XCTAssertEqual(actual, expected, file: file, line: line)
}

private func assertRowTotal(
    _ row: [Int],
    equals expected: Int,
    file: StaticString = #filePath,
    line: UInt = #line
) {
    assertIntegerEqual(
        row.reduce(0, +),
        expected,
        file: file,
        line: line
    )
}

final class NestedTotalHelperTests: XCTestCase {
    func testRowTotal() {
        assertRowTotal([2, 3, 4], equals: 9)
    }
}

Al revisar una cadena de helpers más grande, haz un ejercicio sencillo de seguimiento: empieza en la llamada al test, sigue cada helper y comprueba que la misma ubicación capturada llegue a la aserción. Captura los valores predeterminados en el límite que quieras que aparezca en el resultado; pasa los valores existentes por las demás capas. Evita ocultar la captura detrás de otra función usada como argumento predeterminado, el problema que ilustra SE-0285.

¿Informar un error detiene el test que lo llama?

La atribución del error y el flujo de control son decisiones independientes. continueAfterFailure de XCTest tiene como valor predeterminado true, por lo que la ejecución normalmente continúa después de una aserción fallida. Cambiar el archivo y la línea informados no modifica esa propiedad. Apple documenta este comportamiento en continueAfterFailure.

Si un helper detecta una condición que invalida el resto de su propio trabajo, dale una ruta de salida explícita. Por ejemplo, registra el error con la ubicación pasada y luego retorna desde el helper. Recuerda que retornar desde un helper devuelve el control a quien lo llamó; diseña en consecuencia el trabajo posterior del llamador. La guía de migración de Apple ilustra un error incondicional seguido de un retorno.

Mantén la primera verificación síncrona y pequeña. Comprueba que un cálculo intencionadamente incorrecto falla en el punto de llamada esperado antes de añadir una configuración más elaborada o comportamiento asíncrono. Así separarás un defecto al pasar la ubicación de otros problemas de ejecución de tests.

Usar una ubicación de código fuente compatible en Swift Testing

Para un helper llamado por tests de Swift Testing, usa #expect con un SourceLocation explícito. Apple documenta sourceLocation como la ubicación a la que se atribuyen las expectativas y los problemas, y afirma que una condición falsa registra un problema para el test que se ejecuta en la tarea actual. Consulta expect(_:_:sourceLocation:).

Este archivo alternativo completo requiere Swift Testing, disponible con Xcode 16 y Swift 6.0. Captura los cuatro componentes de ubicación como valores predeterminados independientes y luego construye el inicializador de SourceLocation documentado.

import Testing

private func expectTotal(
    _ values: [Int],
    equals expected: Int,
    fileID: String = #fileID,
    filePath: String = #filePath,
    line: Int = #line,
    column: Int = #column
) {
    let location = SourceLocation(
        fileID: fileID,
        filePath: filePath,
        line: line,
        column: column
    )
    let actual = values.reduce(0, +)
    #expect(actual == expected, sourceLocation: location)
}

@Test func matchingTotal() {
    expectTotal([2, 3, 4], equals: 9)
}

@Test func deliberatelyIncorrectTotal() {
    expectTotal([2, 3, 4], equals: 10)
}

El inicializador requiere un ID de archivo no vacío y con el formato correcto, así como números de línea y columna positivos. Capturar los componentes proporcionados por el compilador evita inventar esos valores. Al anidar estos helpers, pasa los cuatro argumentos capturados, tal como la versión de XCTest pasa sus dos argumentos. De nuevo, corrige la expectativa deliberadamente 10 después de verificar la atribución.

¿Qué cambia cuando XCTest y Swift Testing comparten un helper?

Ambos frameworks pueden coexistir en un mismo paquete de tests, pero un helper que cruza los límites entre frameworks necesita un manejo que tenga en cuenta la versión. La guía de migración actual de Apple documenta la interoperabilidad y sus valores predeterminados: las cadenas de herramientas anteriores a Swift 6.4 usan none; Swift 6.4 o posterior usa por defecto limited para paquetes que declaran una versión anterior de tools y complete para paquetes que declaran la versión de tools 6.4 o posterior.

Modo de interoperabilidad Error de una aserción de XCTest dentro de un test de Swift Testing
none Se ignora el problema entre bibliotecas
limited Se informa como advertencia, con indicaciones para modernizar el código
complete Se conserva la gravedad de error, con indicaciones para modernizar el código
strict Se informa mediante fatalError

Estos modos explican por qué un helper puede informar el texto correcto y, aun así, hacer que un test de Swift Testing pase. La sesión de migración WWDC26 de Apple muestra exactamente este resultado y luego cambia a Complete el ajuste de interoperabilidad del plan de tests en Test Execution para conservar la gravedad de error. Comprueba la cadena de herramientas instalada antes de depender de esta función.

En cadenas de herramientas anteriores, mantén el registro de aserciones nativo de cada framework y comparte la lógica determinista subyacente. Para configuraciones de interoperabilidad compatibles, Apple también muestra cómo sustituir el XCTFail de un helper por Issue.record de Swift Testing. Durante esa migración, sigue siendo necesario preservar el paso de la ubicación del código fuente.

Diagnosticar el síntoma restante

Qué observas Qué inspeccionar a continuación
El error apunta dentro del helper de aserción Confirma que la aserción recibe los argumentos de ubicación capturados
El error apunta dentro de un helper externo Confirma que ese helper externo pasa la ubicación de su llamador
El test de Swift Testing pasa pese a una aserción de XCTest Comprueba la compatibilidad de la cadena de herramientas y el modo de interoperabilidad
El código se ejecuta después de que falle una aserción de XCTest Comprueba el flujo de control previsto y continueAfterFailure
No aparece ningún test de ejemplo en la ejecución Confirma que el archivo pertenece al destino de tests unitarios y que el plan de tests activo lo incluye

Para descubrir y seleccionar tests, la guía de configuración de tests y la guía de ejecución de tests de Apple describen los destinos de tests y los planes activos. Para una comprobación entre frameworks, aplica las reglas de interoperabilidad documentadas antes de cambiar los argumentos de ubicación.

Un helper compartido útil conserva tres cosas: una comparación significativa, un diagnóstico vinculado al llamador previsto y el resultado de test previsto. Verifícalas con una discrepancia intencional, elimínala y sigue pasando la ubicación capturada cada vez que añadas otro nivel de helper.

Fuentes