문서 메뉴
문서 홈
/ /
Atlas Device SDK
/

테스트 및 디버그 - Swift SDK

이 페이지의 내용

  • 테스트
  • 기본 Realm을 사용하여 테스트
  • Realm 인스턴스 주입
  • 클래스 프로젝션으로 테스트 간소화
  • 테스트 대상
  • 디버깅
  • Realm Studio를 사용한 디버깅
  • LLDB
  • 문제 해결
  • 빌드 문제 해결
  • UI 로드 전 Realm 열기 문제
  • 모델에 대해 정의된 속성 없음
  • 할당 불량/사용 가능한 메모리 부족
  • Swift 패키지 대상을 동적으로 빌드할 수 없음

Realm 기반 애플리케이션을 사용하고 테스트하는 가장 쉬운 방법은 기본 Realm을 사용하는 것입니다. 애플리케이션 데이터의 재정의를 방지하고 테스트 간 상태 유출을 막기 위해, 각 테스트마다 기본 Realm을 새 파일로 설정하는 것이 좋습니다.

// A base class which each of your Realm-using tests should inherit from rather
// than directly from XCTestCase
class TestCaseBase: XCTestCase {
override func setUp() {
super.setUp()
// Use an in-memory Realm identified by the name of the current test.
// This ensures that each test can't accidentally access or modify the data
// from other tests or the application itself, and because they're in-memory,
// there's nothing that needs to be cleaned up.
Realm.Configuration.defaultConfiguration.inMemoryIdentifier = self.name
}
}

Realm 관련 코드를 테스트하는 또 다른 방법은 테스트하려는 모든 메서드가 realm 인스턴스를 인수로 받아들이도록 하는 것입니다. 이를 통해 앱을 실행하고 테스트할 때 다양한 Realm을 전달할 수 있습니다.

예를 들어 앱에 JSON API에서 사용자 프로필을 GET 처리하는 메서드가 있다고 가정해 보겠습니다. 로컬 프로필이 제대로 생성되었는지 테스트하려고 합니다:

// Application Code
func updateUserFromServer() {
let url = URL(string: "http://myapi.example.com/user")
URLSession.shared.dataTask(with: url!) { data, _, _ in
let realm = try! Realm()
createOrUpdateUser(in: realm, with: data!)
}
}
public func createOrUpdateUser(in realm: Realm, with data: Data) {
let object = try! JSONSerialization.jsonObject(with: data) as? [String: String]
try! realm.write {
realm.create(User.self, value: object, update: .modified)
}
}
// Test Code
let realmPath = URL(fileURLWithPath: "...")
func testThatUserIsUpdatedFromServer() {
let config = Realm.Configuration(fileURL: realmPath)
let testRealm = try! Realm(configuration: config)
let jsonData = "{\"email\": \"help@realm.io\"}".data(using: .utf8)!
// In our test, we're passing in the testRealm. This is where we'd
// pass in our "real" realm in the application code above.
createOrUpdateUser(in: testRealm, with: jsonData)
XCTAssertEqual(testRealm.objects(User.self).first!.email, "help@realm.io",
"User was not properly updated from server.")
}

버전 10.21.0의 새로운 기능

테스트를 위해 객체 속성의 하위 집합으로 작업하려는 경우 클래스 프로젝션을 만들 수 있습니다. 클래스 프로젝션은 Realm 객체 속성을 전달하거나, 이름을 바꾸거나, 제외할 수 있는 모델 추상화입니다. 이 기능은 뷰 모델 구현을 간소화하는 동시에 Realm을 사용한 테스트도 간소화합니다.

예제

이 예제에서는 클래스 프로젝션 정의 및 사용 페이지에서 객체 모델클래스 프로젝션을 사용합니다.

이 예에서는 전체 객체 모델을 사용하여 Realm 객체를 만듭니다. 그런 다음 객체를 클래스 프로젝션으로 검색하여 해당 속성의 하위 집합만 사용하는 것을 확인합니다.

이 클래스 프로젝션을 사용하면 테스트할 필요가 없는 속성에 액세스하거나 설명할 필요가 없습니다.

func testWithProjection() {
let realm = try! Realm()
// Create a Realm object, populate it with values
let jasonBourne = Person(value: ["firstName": "Jason",
"lastName": "Bourne",
"address": [
"city": "Zurich",
"country": "Switzerland"]])
try! realm.write {
realm.add(jasonBourne)
}
// Retrieve all class projections of the given type `PersonProjection`
// and filter for the first class projection where the `firstName` property
// value is "Jason"
let person = realm.objects(PersonProjection.self).first(where: { $0.firstName == "Jason" })!
// Verify that we have the correct PersonProjection
XCTAssert(person.firstName == "Jason")
// See that `homeCity` exists as a projection property
// Although it is not on the object model
XCTAssert(person.homeCity == "Zurich")
// Change a value on the class projection
try! realm.write {
person.firstName = "David"
}
// Verify that the projected property's value has changed
XCTAssert(person.firstName == "David")
}

Realm 프레임워크를 테스트 대상에 직접 연결하지 마세요. 이로 인해 '객체 유형 'YourObject'가 Realm에서 관리되지 않습니다'라는 예외 메시지와 함께 테스트가 실패할 수 있습니다. 테스트 대상에서 Realm의 연결을 해제하면 이 문제가 해결됩니다.

애플리케이션 또는 프레임워크 대상에서 모델 클래스 파일을 컴파일합니다. 단위 테스트 대상에 추가하지 마세요. 그렇지 않으면 테스트 시 해당 클래스가 중복되어 디버깅하기 어려운 문제가 발생할 수 있습니다.

테스트에 필요한 모든 코드를 단위 테스트 대상에 노출하세요. 액세스 public 한정자 또는 @testable을 사용합니다.

Realm을 동적 프레임워크로 사용하기 때문에 단위 테스트 대상이 Realm을 찾을 수 있는지 확인해야 합니다. 단위 테스트의 "프레임워크 검색 경로" 에 RealmSwift.framework 의 상위 경로를 추가합니다.

Realm Studio를 사용하면 로컬 Realm을 열고 편집할 수 있습니다. Mac, Windows, Linux를 지원합니다.

Realm의 Swift API를 사용하는 앱의 디버깅은 LLDB 콘솔을 통해 수행해야 합니다.

LLDB 스크립트를 사용하면 Xcode의 UI에서 Realm 변수의 내용을 검사할 수 있지만, 아직 Swift에서는 이 기능이 작동하지 않습니다. 이러한 변수는 잘못된 데이터를 표시합니다. 대신 LLDB의 po 명령을 사용하여 Realm에 저장된 데이터의 내용을 검사하세요.

일부 개발자는 CocoaPods 또는 Carthage를 통해 Realm Swift SDK를 설치한 후 빌드 문제를 경험합니다. 이러한 문제의 일반적인 원인은 다음과 같습니다:

  • 설치 문제:

    • 초기 설치에 실패했습니다.

    • 지원되지 않는 버전의 종속성 관리자 사용하기

  • 빌드 도구 문제:

    • 빌드 도구에 오래된 캐시가 있습니다.

    • 빌드 도구 버전 업데이트

  • 다음과 같이 프로젝트 설정을 변경합니다:

    • 새 대상 추가

    • 대상 간에 종속성 공유

이러한 문제는 파생 데이터를 삭제하고 Xcode 빌드 폴더를 정리하면 해결되는 경우가 많습니다.

1

터미널의 프로젝트 루트에서 다음 명령 실행:

pod cache clean Realm
pod cache clean RealmSwift
pod deintegrate || rm -rf Pods
pod install --repo-update --verbose
# Assumes the default DerivedData location:
rm -rf ~/Library/Developer/Xcode/DerivedData
2

Xcode에서 프로젝트를 연 상태에서 제품 드롭다운 메뉴로 이동하여 빌드 폴더 정리를 선택합니다.

제품을 선택한 다음 빌드 폴더 정리를 선택합니다.
클릭하여 확대
1

터미널의 프로젝트 루트에서 다음 명령 실행:

rm -rf Carthage
# Assumes default DerivedData location:
rm -rf ~/Library/Developer/Xcode/DerivedData
carthage update

중요

이렇게 하면 App Services뿐만 아니라 Carthage에서 관리하는 모든 종속성이 업데이트됩니다.

2

Xcode에서 프로젝트를 연 상태에서 제품 드롭다운 메뉴로 이동하여 빌드 폴더 정리를 선택합니다.

제품을 선택한 다음 빌드 폴더 정리를 선택합니다.
클릭하여 확대

Realm을 열 때 선택적 또는 필수 속성과 관련된 오류 메시지로 인해 즉시 충돌이 발생할 수 있습니다. 객체 모델에 문제가 있으면 이러한 유형의 충돌이 발생할 수 있습니다. 이러한 오류는 Realm을 연 후 UI에 도달하기 전에 발생합니다.

장치에서 Realm이 열리는 경우, '스키마 검색' 단계가 진행됩니다. 이때 Realm은 관리하는 모든 객체에 대한 스키마를 검사합니다. 특정 Realm이 애플리케이션에서 객체의 하위 집합만 관리하도록 지정할 수 있습니다.

스키마 검색 중에 속성과 관련된 오류가 표시되는 경우, 이는 특정 객체의 데이터 문제가 아니라 스키마 문제로 인한 것일 수 있습니다. 예를 들어 to-one 관계를 선택 사항이 아닌 필수 사항으로 정의하면 스키마 검색 오류가 표시될 수 있습니다.

이러한 충돌을 디버그하려면 정의한 스키마를 확인하세요.

이는 UI가 로딩되기 전에 발생하므로 스키마 검색 문제임을 알 수 있습니다. 즉, 속성을 잘못 사용하려는 UI 요소가 없으며 잘못된 데이터를 포함할 수 있는 객체가 메모리에 존재하지 않습니다. UI가 로딩된 이후 속성과 관련된 오류가 발생하는 경우 잘못된 스키마 때문일 수 있습니다. 대신 이러한 오류는 부정확하거나 잘못 입력되었거나 누락된 데이터로 인해 발생했을 가능성이 높습니다.

Realm Swift SDK는 런타임에 모델의 속성을 결정하기 위해 Swift 언어의 리플렉션 기능을 사용합니다. 다음과 비슷한 충돌이 발생하면 프로젝트에서 리플렉션 메타데이터를 비활성화하지 않았는지 확인하세요.

Terminating app due to uncaught exception 'RLMException', reason: 'No properties are defined for 'ObjectName'.

SWIFT_REFLECTION_METADATA_LEVEL = none 를 설정하면 Realm은 속성 및 열거형과 같은 하위 유형을 검색할 수 없습니다. 리플렉션은 프로젝트가 이 세팅에 대한 레벨을 구체적으로 설정하지 않는 경우 기본적으로 활성화됩니다.

메모리가 부족한 iOS 또는 iPad 장치나 다수의 Realm 또는 많은 알림을 사용하는 메모리 집약적인 애플리케이션을 사용하는 경우 다음과 같은 오류가 발생할 수 있습니다.

libc++abi: terminating due to an uncaught exception of type std::bad_alloc: std::bad_alloc

이 오류는 일반적으로 사용 가능한 메모리가 부족하여 리소스를 할당할 수 없음을 나타냅니다.

iOS + 또는 iPad +용으로 빌드하는 경우 확장 15 15 가상 주소 지정 권한 을 추가할 수 있습니다. 을(를) 클릭하여 이 문제를 해결하세요.

속성 목록에 다음 키를 추가하고 값을 true 으로 설정합니다.

<key>com.apple.developer.kernel.extended-virtual-addressing</key>
<true/>
<key>com.apple.developer.kernel.increased-memory-limit</key>
<true/>

버전 10 에서 변경되었습니다.49.3.

Swift SDK v10.49.3 Swift Package Manager(SPM)로 패키지를 설치하기 위한 세부 정보를 변경했습니다. 패키지의 이전 버전에서 v10 로 업데이트하는 경우.49.3 이상에서는 다음과 유사한 빌드 오류가 발생할 수 있습니다.

Swift package target `Realm` is linked as a static library by `TargetName`
and `Realm`, but cannot be built dynamically because there is a package
product with the same name.

이 오류를 해결하려면 빌드 대상에서 Realm 또는 RealmSwift 패키지의 연결을 해제하세요. 다음 단계에 따라 Xcode에서 이 작업을 수행할 수 있습니다.

  1. Targets 프로젝트에서 빌드 대상을 선택합니다.

  2. Build Phases 탭으로 이동합니다.

  3. Link Binary With Libraries 요소를 확장합니다.

  4. Realm 또는 RealmSwift 을(를) 선택하고 항목 제거(-) 버튼을 클릭하여 불필요한 바이너리를 제거합니다.

    • Swift 또는 Swift 및 오브젝티브-C API를 사용하는 경우 RealmSwift 을(를) 유지합니다.

    • 오브젝티브-C API만 사용하는 경우 Realm 을(를) 유지합니다.

이제 대상이 이 오류 없이 빌드되어야 합니다.

돌아가기

Swift 동시성

다음

로깅