コンテンツにスキップ

02. Firebase Emulatorで安全に検証する

Firebaseをアプリに接続すると、設定を間違えたテストコードが本番データを読み書きする危険があります。ローカル開発では、まずFirebase Emulator Suiteに接続し、ルールとデータの境界を確認します。

Firebase Local Emulator Suiteでは、Authentication、Cloud Firestore、Cloud Storage、Cloud Functionsなどを組み合わせてローカル検証できます。Firebase公式ドキュメントでは、ユニットテスト、統合テスト、手動テストの用途が説明されています。

HabitFlowでは、まず次の構成から始めます。

機能確認すること
Authentication未ログイン、本人、別ユーザーの状態
Firestore読み取り、作成、更新、削除の許可
Storage本人のファイルだけを扱えるか
Functions認証、入力制限、失敗時の応答

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

起動時には、必ずテスト用プロジェクトを指定します。

Terminal window
firebase emulators:start --project demo-habitflow

テスト用プロジェクトIDを明示しないと、意図せず別の設定を読み込むことがあります。アプリ側でも、開発環境でだけ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で接続先が異なる場合は、環境変数や設定ファイルで切り替えます。

ルールは、許可されるケースだけでなく拒否されるケースをテストします。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、クライアントのどこで認可するかを説明できる