클라우드 Mac에서 iOS 드래그 앤 드롭 데이터 검증하기

CI/CD ·약 9분 읽기

클라우드 Mac에서 iOS 드래그 앤 드롭 데이터 검증하기

릴리스 직전, 팀은 목록에 있는 작업 번호를 편집 영역으로 드래그했습니다. 드래그 미리보기는 정상이고 놓을 때 오류도 없었지만, 저장된 값은 빈 문자열이었습니다. 원인은 애니메이션이 아닙니다. 드래그 소스가 선언한 데이터 형식, 드롭 대상이 허용하는 형식, 비동기 읽기가 완료되는 시점 중 하나라도 어긋나면 화면은 성공한 것처럼 보일 수 있습니다. 클라우드 Mac에서 원격으로 작업할 때는 먼저 XCTest로 데이터 계약을 확인하고, 그다음 시뮬레이터에서 실제 제스처를 검증할 수 있습니다. 어느 한쪽이 다른 쪽을 대신할 수는 없습니다.

드래그 앤 드롭 규약을 검증 가능한 계약으로 정의하기

드래그할 수 있는 콘텐츠마다 세 가지를 기록합니다. 제공자가 선언하는 UTType, 드롭 대상이 허용하는 형식, 읽기에 성공했을 때 얻어야 하는 내용입니다. 예를 들어 작업 번호를 텍스트 필드에 붙여 넣을 문자열로만 사용한다면 양쪽에서 UTType.utf8PlainText를 사용하기로 정할 수 있습니다. 보내는 쪽은 일반 텍스트로 등록했는데 받는 쪽은 이미지 형식만 조회하면서, “드롭 동작이 실행됐다”는 이유로 성공했다고 판단해서는 안 됩니다.

오류 처리 방식도 명시해야 합니다. 지원하지 않는 형식은 드롭할 수 있는 대상으로 강조 표시하지 않아야 하고, 읽기에 실패했다면 빈 작업 항목을 삽입하지 않아야 합니다. 드래그를 취소해도 원본 데이터는 바뀌면 안 됩니다. 작업 번호 외의 필드를 보존해야 한다면 구조화된 데이터를 표시용 텍스트에 몰래 넣지 말고, 별도의 데이터 형식을 정의해 양쪽에서 파싱하도록 해야 합니다.

드롭이 끝났다는 것은 UI 이벤트가 발생했다는 뜻이지, 데이터가 반영됐다는 뜻이 아닙니다. 형식이 일치하고 비동기 읽기와 내용 검증까지 성공한 뒤에만 비즈니스 상태를 업데이트해야 합니다.

XCTest로 형식과 실제 페이로드 검증하기

앱의 테스트 target에 테스트 파일을 추가합니다. 아래 제공자는 UTF-8 텍스트를 등록합니다. 테스트는 먼저 형식을 확인한 뒤 읽기 콜백을 기다리고, 읽어 온 바이트를 검증합니다. 마우스나 그래픽 데스크톱에 의존하지 않아 빌드 파이프라인에서 먼저 실행하는 빠른 검사에 적합합니다.

import XCTest
import UniformTypeIdentifiers

final class DragPayloadTests: XCTestCase {
    func testPlainTextPayload() {
        let provider = NSItemProvider()
        provider.registerDataRepresentation(
            forTypeIdentifier: UTType.utf8PlainText.identifier,
            visibility: .all
        ) { completion in
            completion(Data("ticket-42".utf8), nil)
            return nil
        }

        XCTAssertTrue(provider.hasItemConformingToTypeIdentifier(
            UTType.plainText.identifier
        ))
        XCTAssertFalse(provider.hasItemConformingToTypeIdentifier(
            UTType.image.identifier
        ))

        let loaded = expectation(description: "Load drag payload")
        provider.loadDataRepresentation(
            forTypeIdentifier: UTType.utf8PlainText.identifier
        ) { data, error in
            XCTAssertNil(error)
            XCTAssertEqual(data.flatMap { String(data: $0, encoding: .utf8) },
                           "ticket-42")
            loaded.fulfill()
        }
        wait(for: [loaded], timeout: 5)
    }
}

여기서는 plainText로 호환되는 형식을 확인하고, utf8PlainText로 등록된 구체적인 표현을 읽습니다. 테스트가 통과하면 제품 코드에도 동일한 형식 판단과 디코딩 로직을 적용하세요. 테스트에서는 한 형식을 허용하고 화면에서는 다른 허용 목록을 사용하는 일을 피할 수 있습니다. 실제 앱의 콜백에서는 error, 빈 데이터, UTF-8 디코딩 실패도 처리해야 합니다. hasItemConformingToTypeIdentifier 결과만으로 화면을 수정해서는 안 됩니다.

시뮬레이터 대상을 지정한 뒤 실행하기

먼저 VMCommit 콘솔에서 현재 선택 가능한 구성을 확인합니다. Mac을 인도받은 뒤에는 SSH로 접속해 설치된 시뮬레이터를 확인합니다. 아래의 프로젝트, Scheme, 기기 식별자를 자신의 값으로 바꾸세요. 기기 식별자는 첫 번째 명령에서 확인해야 하며, 예시 문자열을 실제 기기로 사용해서는 안 됩니다.

xcrun simctl list devices available
xcodebuild -list -project App.xcodeproj
xcodebuild test \
  -project App.xcodeproj \
  -scheme App \
  -destination 'platform=iOS Simulator,id=YOUR_DEVICE_ID' \
  -only-testing:AppTests/DragPayloadTests

-only-testing 경로는 프로젝트의 테스트 target 및 클래스 이름과 일치해야 합니다. Scheme이 없다는 메시지가 나오면 먼저 공유 설정을 확인하세요. 대상 기기를 사용할 수 없다면 다른 Mac의 식별자를 재사용하지 말고 현재 Mac의 목록을 다시 조회하세요. 테스트가 실패하면 원본 출력을 먼저 보관해 “시뮬레이터가 시작되지 않음”과 “페이로드 검증 실패”를 구분합니다.

그래픽 세션에서 실제 드롭 검증하기

계약 테스트는 제스처 처리를 거치지 않으므로 UIDragInteraction이나 UIDropInteraction이 올바르게 연결됐다는 보장은 없습니다. 그래픽 데스크톱에서 시뮬레이터를 열고 테스트 앱을 설치한 다음, 아래 순서로 전체 동작을 확인합니다.

  1. 유효한 원본 항목을 길게 눌러 드래그를 시작하고, 미리보기가 선택한 항목과 일치하는지 확인합니다.
  2. 허용된 대상으로 옮겨 드롭 가능 피드백이 나타나는지 확인합니다. 해당 형식을 받지 않는 영역으로 옮겼을 때는 피드백이 사라져야 합니다.
  3. 놓은 뒤 읽기가 끝날 때까지 기다리고, 편집 영역에 정확한 작업 번호가 한 번만 삽입됐는지 확인합니다.
  4. 다시 드래그한 다음 놓기 전에 취소하고, 목록과 편집 영역이 모두 그대로인지 확인합니다.

페이로드가 크다면 “읽는 중”을 별도 상태로 다루세요. 중복 제출을 막고 읽기가 끝난 뒤 내용을 업데이트해야 합니다. 실패하면 다시 조작할 수 있는 상태로 되돌리고 명확한 안내를 표시합니다. 애니메이션을 매끄럽게 보이게 하려고 비동기 콜백이 반환되기 전에 “가져오기 완료”를 표시해서는 안 됩니다. 그래픽 검증은 사용자가 보는 상태 변화를, XCTest는 내부 데이터를 확인합니다. 두 결과는 각각 기록해야 합니다.

실패 원인은 데이터 흐름을 따라 추적하기

“대상이 강조 표시되지 않는다”면 먼저 형식을 확인하세요. 개발 환경에서 소스가 등록한 식별자와 대상이 허용하는 식별자를 출력하고, 표시 이름만 비교하는 대신 형식 호환성을 확인하는지 살펴봅니다. “대상은 강조되지만 내용이 없다”면 로드 콜백의 실행 여부와 오류, 데이터 길이, 디코딩 결과를 확인합니다. 페이로드 전체를 공유 로그에 남기지는 마세요. 작업 내용에 업무 데이터가 포함될 수 있으며, 형식과 길이만 기록해도 경계를 파악하는 데는 대체로 충분합니다.

“가끔 두 번 삽입된다”면 드롭 콜백과 로드 완료 콜백에서 모두 모델을 업데이트하거나, 같은 제공자에 대해 읽기를 중복 시작하는지 확인하세요. 드롭마다 작업 식별자를 하나씩 부여하고 검증에 성공한 뒤 한 번만 반영합니다. 취소되거나 실패한 경우에는 반영 대기 중인 결과를 버립니다. 이미지 등 다른 페이로드로 전환한다면 허용하는 형식마다 테스트를 따로 작성하세요. 일반 텍스트가 통과했다고 모든 드래그 앤 드롭 경로가 동작한다고 가정해서는 안 됩니다.

인도 전 두 가지 결과표 대조하기

자동화 결과표에는 형식 일치, 미지원 형식 거부, 바이트 내용 일치, 빈 값과 읽기 오류 처리, 시간 초과 시 테스트 실패 여부가 포함돼야 합니다. 그래픽 결과표에는 올바른 소스 미리보기와 대상 피드백, 성공 후 한 번만 업데이트되는지, 취소 후 내용이 유지되는지, 실패 안내를 성공으로 잘못 표시하지 않는지가 포함돼야 합니다. 전자는 커밋할 때마다 실행하기 좋고, 후자는 인터랙션 구현이나 시스템 버전이 바뀐 뒤 집중적으로 재확인해야 합니다.

마지막으로 초기 상태의 시뮬레이터에서 작업을 반복해, 이전 실행에서 편집 영역에 남은 내용에 결과가 의존하지 않는지 확인합니다. 프로젝트에서 실제로 허용하는 형식과 두 결과표를 함께 보관하면 다음에 드래그 앤 드롭 형식을 변경할 때 문제가 데이터 계약, 비동기 읽기, 제스처 피드백 중 어디에 있는지 판단할 수 있습니다.

자주 묻는 질문

NSItemProvider 테스트만으로 드롭 UI도 검증할 수 있나요?

아니요. 데이터 형식과 읽기는 검증할 수 있지만, 미리 보기와 드롭 대상 표시, 취소 피드백은 그래픽 화면에서 확인해야 합니다.

수신 측은 언제 데이터를 가져와야 하나요?

먼저 허용하는 UTType과 일치하는지 확인하고 비동기로 읽으세요. 완료 콜백 전에는 가져오기가 끝난 것으로 처리하지 마세요.

필요한 기간만큼 대여

독립형 Mac mini로 다음 단계를 검증하세요

VMCommit은 M4 독립형 Mac mini를 일간, 주간, 월간 또는 분기 단위로 대여합니다. 모델과 위치를 선택한 뒤 콘솔에서 실시간 이용 가능 여부를 확인하세요.

Mac mini 지금 대여하기