Xcode에서 공유 XCTest 헬퍼를 호출한 테스트를 강조 표시하려면, 헬퍼에 기본값이 있는 #filePath 및 #line 매개변수를 지정하고 두 값을 모두 어설션에 전달하세요. 이 안내에서는 수정 방법과 중첩 헬퍼, Swift Testing에서의 동일한 방법을 보여 줍니다.

Xcode는 왜 헬퍼를 강조 표시하나요?

공유 어설션을 사용하면 소스 위치가 하나 더 생깁니다. 테스트가 헬퍼를 호출하고, 헬퍼는 XCTest 어설션을 호출합니다. 이 어설션이 기본 위치 인수를 사용하면, 보고되는 위치는 헬퍼 내부의 어설션입니다. Apple은 XCTAssertEqual과 XCTFail 모두에서 file: StaticString = #filePath 및 line: UInt = #line를 문서화합니다.

헬퍼의 경계에서 호출자의 위치를 캡처한 다음, 그 값을 다음 단계로 전달하세요. Swift의 소스 위치 기본값은 호출 지점을 캡처합니다. Swift 프로젝트는 SE-0274: 간결한 매직 파일 이름에서 이 동작을 설명합니다. Apple은 Swift Testing으로 마이그레이션에서도 이 XCTest 헬퍼 패턴을 직접 보여 주며, Xcode가 실패를 헬퍼 호출에 귀속하는 모습을 설명합니다.

Mac에서 Xcode를 사용하는 개발자의 구체적인 목표는 재사용 가능한 검사를 유지하면서 각 실패가 관련 테스트 입력으로 이어지게 하는 것입니다. 아래 예제에서는 작은 정수 배열만 사용합니다. 실행 시 앱 모델, 서비스 대체물, 다운로드한 종속성 또는 네트워크 액세스가 필요하지 않습니다.

XCTest 헬퍼에 호출자 위치 매개변수 추가하기

기존 macOS 단위 테스트 대상을 사용하세요. 프로젝트에 대상이 없다면 File > New > Target을 선택하고, Test를 필터링한 다음 Unit Testing Bundle을 선택하세요. 테스트 파일을 추가하려면 File > New > New File From Template을 선택하고 XCTest Unit Test를 선택하세요. Apple은 Xcode 프로젝트에 테스트 추가하기에서 이 경로를 문서화합니다.

이 전체 테스트 파일을 해당 단위 테스트 대상에 배치하세요. 두 번째 테스트는 실패 위치를 확인할 수 있도록 예상 합계를 의도적으로 잘못 지정합니다.

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)
    }
}

중요한 부분은 매개변수 유형과 기본값, 명시적인 전달입니다. StaticString과 UInt는 XCTest의 어설션 시그니처와 일치합니다. #filePath와 #line은 헬퍼의 기본값에 직접 두세요. 그러면 테스트는 위치 인수를 직접 지정하지 않고 헬퍼를 호출합니다. 문서화된 XCTAssertEqual 매개변수를 참조하세요.

산술은 예시를 위한 것입니다. 2 + 3 + 4은 9이므로 첫 번째 비교는 일치하고 두 번째는 일치하지 않습니다. 이 산술 사례는 Python으로 로컬에서 확인했습니다. 조사 환경에서 Swift 실행 파일을 사용할 수 없어 Swift 예제를 검토했지만 여기서 컴파일하거나 실행하지는 않았습니다.

위치와 테스트 결과 확인하기

Product > Test를 선택하거나 선언 옆의 실행 컨트롤을 사용해 개별 테스트를 실행하세요. 그런 다음 Test navigator에서 실패한 테스트를 선택하고 진단 정보를 확인하세요. Apple은 테스트 실행 및 결과 해석하기에서 이 컨트롤과 실패 세부 정보를 설명합니다.

이 예제에서는 두 가지 결과를 따로 확인하세요. testDeliberatelyIncorrectTotal()이 실패하고, 해당 어설션 진단은 assertTotal([2, 3, 4], equals: 10) 호출을 가리켜야 합니다. 예상한 호출자 귀속은 Apple이 보여 준 전달 패턴에 따릅니다. 확인한 뒤 10를 9로 바꾸고 테스트를 다시 실행하세요. 의도적인 불일치는 완성된 테스트 스위트에서 제거해야 합니다.

진단이 여전히 헬퍼 내부를 가리킨다면 마지막 어설션 호출을 확인하세요. 실패를 기록하는 지점에서 헬퍼가 file: file 또는 line: line을 생략하면 위치 매개변수를 선언하는 것만으로는 충분하지 않습니다.

모든 헬퍼 계층에서 위치 유지하기

중첩 헬퍼에서도 동일하게 명시적으로 전달해야 합니다. 테스트가 도메인 헬퍼를 호출하고, 그 헬퍼가 더 낮은 수준의 어설션 헬퍼를 호출한다고 가정해 보세요. 바깥 헬퍼가 위치 인수를 생략하면 낮은 수준의 헬퍼는 그 중간 호출 지점을 캡처합니다.

여기서 확인할 언어 경계가 있습니다. 소스 위치 기본값은 임의의 헬퍼 호출을 거쳐 자동으로 전달되지 않습니다. SE-0285: 간결한 매직 파일 문자열로의 전환 간소화에서는 기본값의 비전이 동작을 명시적으로 다룹니다.

다음은 완전한 대체 테스트 파일입니다. 원래 테스트 위치를 유지하면서 한 헬퍼가 다른 헬퍼를 호출하는 방법을 보여 줍니다.

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)
    }
}

더 긴 헬퍼 체인을 검토할 때는 간단한 추적 연습을 해 보세요. 테스트 호출에서 시작해 각 헬퍼를 따라가며 동일하게 캡처된 위치가 어설션까지 전달되는지 확인하세요. 결과에 표시할 경계에서 기본값을 캡처하고 나머지 계층에는 기존 값을 전달하세요. SE-0285에서 설명한 문제처럼, 다른 함수 호출을 기본 인수에 넣어 캡처를 감추지 마세요.

실패를 보고하면 호출 중인 테스트가 중단되나요?

실패 귀속과 제어 흐름은 별개의 결정입니다. XCTest의 continueAfterFailure 기본값은 true이므로, 어설션이 실패해도 일반적으로 실행이 계속됩니다. 보고되는 파일과 줄을 바꿔도 이 동작은 바뀌지 않습니다. Apple은 continueAfterFailure에서 이 동작을 문서화합니다.

헬퍼가 남은 작업을 무효화하는 조건을 감지한다면 명시적인 종료 경로를 제공하세요. 예를 들어 전달받은 위치를 사용해 실패를 기록한 다음 헬퍼에서 반환합니다. 헬퍼에서 반환하면 호출자에게 제어가 돌아가므로, 호출자에서 이어지는 작업도 그에 맞게 설계하세요. Apple의 마이그레이션 가이드에는 무조건 실패를 기록한 뒤 반환하는 예제가 있습니다.

첫 번째 확인은 동기식으로 간단하게 진행하세요. 더 복잡한 설정이나 비동기 동작을 추가하기 전에 의도적으로 잘못된 계산이 예상한 호출 지점에서 실패하는지 확인합니다. 이 순서를 따르면 위치 전달 문제와 다른 테스트 실행 문제를 구분할 수 있습니다.

Swift Testing에서 지원되는 소스 위치 사용하기

Swift Testing 테스트에서 호출하는 헬퍼에는 명시적인 SourceLocation과 함께 #expect를 사용하세요. Apple은 sourceLocation를 기대 사항과 이슈가 귀속되는 위치로 문서화하고, 조건이 거짓이면 현재 작업에서 실행 중인 테스트에 대한 이슈가 기록된다고 설명합니다. expect(_:_:sourceLocation:)를 참조하세요.

이 완전한 대체 파일에는 Xcode 16 및 Swift 6.0에서 사용할 수 있는 Swift Testing이 필요합니다. 문서화된 SourceLocation 이니셜라이저를 구성하기 전에 위치 구성 요소 네 개를 각각 별도의 기본값으로 캡처합니다.

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)
}

이니셜라이저에는 올바른 형식의 비어 있지 않은 파일 ID와 양수인 줄 번호 및 열 번호가 필요합니다. 컴파일러가 제공하는 구성 요소를 캡처하면 이 값을 임의로 만들어 낼 필요가 없습니다. 이러한 헬퍼를 중첩할 때는 XCTest 버전에서 두 인수를 전달하는 것처럼 캡처한 인수 네 개를 모두 전달하세요. 여기서도 귀속을 확인한 다음 의도적인 10 기대값을 바로잡으세요.

XCTest와 Swift Testing이 헬퍼를 공유하면 무엇이 달라지나요?

두 프레임워크는 하나의 테스트 번들에 함께 있을 수 있지만, 프레임워크 경계를 넘는 헬퍼에는 버전별 처리가 필요합니다. Apple의 최신 마이그레이션 가이드는 상호 운용성과 기본값을 설명합니다. Swift 6.4 이전의 도구 체인은 none을 사용합니다. Swift 6.4 이상은 이전 도구 버전을 선언한 패키지에 limited을, 도구 버전 6.4 이상을 선언한 패키지에 complete를 기본값으로 사용합니다.

상호 운용 모드 Swift Testing 테스트 안에서 발생한 XCTest 어설션 실패
none 프레임워크 간 이슈가 무시됨
limited 현대화 안내와 함께 경고로 보고됨
complete 현대화 안내와 함께 실패 심각도가 유지됨
strict fatalError를 사용해 보고됨

이러한 모드 때문에 헬퍼가 올바른 텍스트를 보고해도 Swift Testing 테스트가 통과할 수 있습니다. Apple의 WWDC26 마이그레이션 세션에서는 정확히 이 결과를 보여 준 다음, 실패 심각도를 유지하도록 Test Execution에서 테스트 계획의 상호 운용 설정을 Complete로 변경합니다. 이 기능에 의존하기 전에 설치된 도구 체인을 확인하세요.

오래된 도구 체인에서는 각 프레임워크에 맞는 방식으로 어설션을 보고하고, 그 아래의 결정적 계산을 공유하세요. 지원되는 상호 운용 구성에서는 헬퍼의 XCTFail을 Swift Testing의 Issue.record로 바꾸는 방법도 Apple이 보여 줍니다. 마이그레이션 중에도 소스 위치 전달은 유지해야 합니다.

남아 있는 증상 진단하기

관찰되는 현상 다음에 확인할 항목
실패가 어설션 헬퍼 내부를 가리킴 캡처된 위치 인수가 어설션에 전달되는지 확인
실패가 바깥 헬퍼 내부를 가리킴 바깥 헬퍼가 호출자의 위치를 전달하는지 확인
XCTest 어설션에도 Swift Testing 테스트가 통과함 도구 체인 지원과 상호 운용 모드 확인
XCTest 어설션 실패 뒤에도 코드가 실행됨 의도한 제어 흐름과 continueAfterFailure 확인
실행 결과에 예제 테스트가 나타나지 않음 파일이 단위 테스트 대상에 속하고 활성 테스트 계획에 포함되어 있는지 확인

테스트 검색과 선택에 관한 내용은 Apple의 테스트 설정 가이드와 테스트 실행 가이드에서 테스트 대상 및 활성 계획을 설명합니다. 프레임워크를 함께 사용하는 테스트가 통과하는 문제라면 위치 인수를 바꾸기 전에 위에 설명된 상호 운용 규칙을 확인하세요.

유용한 공유 헬퍼는 세 가지를 유지합니다. 의미 있는 비교, 의도한 호출자에 연결된 진단 정보, 그리고 의도한 테스트 결과입니다. 의도적인 불일치 하나로 이를 확인하고, 불일치를 제거한 다음, 헬퍼 계층을 추가할 때마다 캡처한 위치를 계속 전달하세요.

출처