02. Firebase Emulatorで安全に検証する
Firebaseをアプリに接続すると、設定を間違えたテストコードが本番データを読み書きする危険があります。ローカル開発では、まずFirebase Emulator Suiteに接続し、ルールとデータの境界を確認します。
1. Emulator Suiteで確認できるもの
Section titled “1. Emulator Suiteで確認できるもの”Firebase Local Emulator Suiteでは、Authentication、Cloud Firestore、Cloud Storage、Cloud Functionsなどを組み合わせてローカル検証できます。Firebase公式ドキュメントでは、ユニットテスト、統合テスト、手動テストの用途が説明されています。
HabitFlowでは、まず次の構成から始めます。
| 機能 | 確認すること |
|---|---|
| Authentication | 未ログイン、本人、別ユーザーの状態 |
| Firestore | 読み取り、作成、更新、削除の許可 |
| Storage | 本人のファイルだけを扱えるか |
| Functions | 認証、入力制限、失敗時の応答 |
2. ルールとEmulatorを設定する
Section titled “2. ルールとEmulatorを設定する”firebase.json で、ルールとEmulatorの利用ポートを明示します。
{ "firestore": { "rules": "firestore.rules", "indexes": "firestore.indexes.json" }, "storage": { "rules": "storage.rules" }, "emulators": { "auth": { "port": 9099 }, "firestore": { "port": 8080 }, "storage": { "port": 9199 }, "functions": { "port": 5001 }, "ui": { "enabled": true, "port": 4000 } }}起動時には、必ずテスト用プロジェクトを指定します。
firebase emulators:start --project demo-habitflowテスト用プロジェクトIDを明示しないと、意図せず別の設定を読み込むことがあります。アプリ側でも、開発環境でだけEmulatorへ接続する分岐を用意し、本番ビルドからは無効になることを確認します。
3. アプリをEmulatorへ接続する
Section titled “3. アプリをEmulatorへ接続する”接続先は、実行環境によって変わります。Android Emulatorからホストマシンへ接続する場合は localhost ではなく 10.0.2.2 を使うなど、端末ごとのアドレスを確認します。
import { connectAuthEmulator, getAuth } from 'firebase/auth';import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore';
const auth = getAuth(app);const db = getFirestore(app);
if (__DEV__) { connectAuthEmulator(auth, 'http://127.0.0.1:9099', { disableWarnings: true, }); connectFirestoreEmulator(db, '127.0.0.1', 8080);}同じ接続処理を複数回実行するとエラーになるため、初期化処理を一度だけ通る構造にします。実機、Android Emulator、iOS Simulatorで接続先が異なる場合は、環境変数や設定ファイルで切り替えます。
4. ルールをテストする
Section titled “4. ルールをテストする”ルールは、許可されるケースだけでなく拒否されるケースをテストします。FirebaseのRules Unit Testingでは、未ログイン、ログイン済みのユーザー、別ユーザーを模したテストコンテキストを作れます。Firestoreルールのテスト方法を参照してください。
最低限、次の組み合わせを用意します。
| 状態 | 本人のデータ | 別ユーザーのデータ |
|---|---|---|
| 未ログイン | 拒否 | 拒否 |
| ログイン済み | 許可 | 拒否 |
| 不正な入力 | 拒否 | 拒否 |
import { doc, getDoc } from 'firebase/firestore';import { assertFails, assertSucceeds } from '@firebase/rules-unit-testing';
await assertSucceeds(getDoc(doc(alice.firestore(), 'users/alice')));await assertFails(getDoc(doc(alice.firestore(), 'users/bob')));await assertFails(getDoc(doc(unauthenticated.firestore(), 'users/alice')));ルールのテストが通っても、Cloud FunctionsやAdmin SDK側の認可が自動的に保証されるわけではありません。サーバー側でもユーザーID、入力値、所有権、管理者権限を検証します。
- 本番プロジェクトを使わずにEmulatorを起動できる
- アプリをAuthenticationとFirestoreのEmulatorへ接続できる
- 本人、別ユーザー、未ログインの3状態をテストできる
- ルール、Functions、クライアントのどこで認可するかを説明できる