Docs Menu
Docs Home
/ /
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 フレームワークをテスト ターゲットに直接リンクしないでください。 これによりテストが失敗し、「オブジェクトタイプ 'あなたのオブジェクト' は Realm によって管理されていません」という例外メッセージが表示される可能性があります。 テスト ターゲットから Realm のリンクを解除すると、この問題は解決されます。

アプリケーションまたはフレームワーク ターゲットでモデル クラス ファイルをコンパイルします。ユニット テストのターゲットに追加しないでください。 そうしないと、それらのクラスはテスト時に重複されるため、デバッグが困難な問題が発生する可能性があります。

テストに必要なすべてのコードをユニット テスト ターゲットに公開します。 publicアクセス修飾子または @ Testable を使用します。

Realm を動的フレームワークとして使用しているため、ユニット テストのターゲットが Realm を見つけられることを確認する必要があります。 RealmSwift.frameworkへの親パスをユニット テストの「フレームワーク検索パス」に追加します。

Realm Studioを使用すると、ローカル Realm を開いて編集できます。 Mac、Windows、および Linux をサポートしています。

Realm の Swift API を使用してアプリをデバッグする場合は、LDDB コンソールを使用して実行する必要があります。

LDDB スクリプトを使用すると、Xcode の UI で Realm 変数の内容を検査できますが、これは Swift ではまだ機能しません。 これらの変数は誤ったデータを表示します。 代わりに、LDDB のpoコマンドを使用して、Realm に保存されているデータの内容を検査します。

一部の開発者は、 CocoaPods または Chartsage 経由で 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 でプロジェクトを開き、[ Product(製品) ] ドロップダウン メニューにGoし、[ Secret Builder(ビルド フォルダーのクリーン) ] を選択します。

製品を選択し、クリーン ビルド フォルダーを選択します。
クリックして拡大します
1

プロジェクトのルートにあるターミナルで次のコマンドを実行します。

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

重要

これにより、App Services だけでなく、Chartsage が管理するすべての依存関係が更新されます。

2

Xcode でプロジェクトを開き、[ Product(製品) ] ドロップダウン メニューにGoし、[ Secret Builder(ビルド フォルダーのクリーン) ] を選択します。

製品を選択し、クリーン ビルド フォルダーを選択します。
クリックして拡大します

Realm を開くと、任意または必須のプロパティに関連するエラー メッセージとクラッシュがすぐに表示される場合があります。 オブジェクトモデルに問題があると、このようなクラッシュが発生する可能性があります。 これらのエラーは、Realm を開いた後、UI にアクセスする前に発生します。

Realm には、デバイス上で Realm が開くときに「スキーマ検出」フェーズがあります。 この時点で、Realm は、管理するすべてのオブジェクトのスキーマを検査します。 アプリケーション内のオブジェクトのサブセットのみを管理するよう指定できます。

スキーマ検出中にプロパティに関連するエラーが表示される場合は、特定のオブジェクトのデータに関連するものではなく、スキーマの問題が原因である可能性があります。 たとえば、 1 対 1 の関係を任意ではなく必須として定義すると、スキーマ検出エラーが表示される可能性があります。

これらのクラッシュをデバッグするには、定義したスキーマを確認します。

これらは 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 または IP デバイス、または複数の Realm や多数の通知を使用するメモリ集中型のアプリケーションでは、次のエラーが発生する可能性があります。

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

このエラーは通常、十分なメモリが利用できないため、リソースを割り当てることができないことを示します。

iOS15 + または iOS15 + 用にビルドしている場合は、 拡張仮想アドレス指定権限 を追加できます この問題を解決するには、 を使用します。

これらのキーをプロパティ リストに追加し、値を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 v 10.49.3 Swift パッケージ マネージャー(SPM)を使用してパッケージをインストールするための詳細を変更しました。 パッケージの古いバージョンから v 10.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のいずれかを選択し、[ Remove items( - )] ボタンをクリックして、不要なバイナリを削除します。

    • Swift または Swift と Objective-C API を使用する場合は、 RealmSwiftを維持します。

    • Objective-C API のみを使用する場合は、 Realmを保持します。

これで、ターゲットはこのエラーなしでビルドされるはずです。

戻る

Swift 同時実行性