建構單元測試

Firebase Local Emulator Suite 可讓您更輕鬆地完整驗證應用程式的 特徵和行為這部 很適合驗證 Firebase Security Rules 設定。使用 Firebase 模擬器 在本機環境中執行及自動化單元測試。在 Cloud 控制台中 這份文件應該可以協助你為應用程式建構及自動執行單元測試 驗證 Rules

如果尚未設定 Firebase Emulator,請先進行設定。

執行模擬器之前

開始使用模擬器前,請注意下列事項:

  • 模擬器一開始會載入 firestore.rules 中指定的規則 或「storage.rules」欄位的值firebase.json。如果檔案沒有 且未使用 loadFirestoreRules 或「loadStorageRules」種方式 如下所述,模擬器會將所有專案視為有開放規則。
  • 雖然 大部分 Firebase SDK 只能直接和模擬器搭配使用,只有 @firebase/rules-unit-testing 程式庫支援 模擬安全性規則中的 auth 可簡化單元測試。此外, 程式庫支援幾項模擬器專屬功能,例如清除所有資料 說明。
  • 模擬器也會接受你提供的正式版 Firebase 驗證權杖 並透過用戶端 SDK 據此評估規則 即可將您的應用程式直接傳送至模擬器,並進行手動測試。

資料庫模擬器與正式環境之間的差異

  • 您不必明確建立資料庫執行個體。模擬器會自動建立任何可存取的資料庫例項。
  • 每個新資料庫都會啟用封閉規則,因此非管理員使用者無法讀取或寫入資料。
  • 每個模擬的資料庫都會套用 Spark 方案 上限和配額 (最值得注意的是,這個上限是每個執行個體將並行數量限制為 100 個 連線)。
  • 任何資料庫都會接受 "owner" 字串做為管理員驗證權杖。
  • 模擬器目前無法與其他 Firebase 互動 很少直接解答該如何打造產品值得注意的是,一般 Firebase 驗證流程無法運作。 您可以改為在 rules-unit-testing 中使用 initializeTestApp() 方法 會採用 auth 欄位透過此參數建立的 Firebase 物件 方法就如同 提供的實體如果傳入 null,系統會視為 未經驗證的使用者 (例如 auth != null 規則將失敗)。

Realtime Database 模擬器互動

實際工作環境的 Firebase Realtime Database 執行個體可在以下的子網域存取: firebaseio.com,而您可以按照以下方式存取 REST API:

https://<database_name>.firebaseio.com/path/to/my/data.json

模擬器會在本機執行,並可從 localhost:9000 取得。如要與特定資料庫執行個體互動,您必須使用 ns 查詢參數指定資料庫名稱。

http://localhost:9000/path/to/my/data.json?ns=<database_name>

使用第 9 版 JavaScript SDK 執行本機單元測試

Firebase 發布了同時包含兩個版本的安全性規則單元測試程式庫 9 JavaScript SDK 和第 8 版 SDK。程式庫 API 主要 也不一樣建議您使用更精簡的 v9 測試程式庫 連線至模擬器所需的設定較少,因此可以安全避免意外 控管正式環境資源的方式為了兼顧回溯相容性,我們會持續 可用的 v8 測試程式庫

使用 @firebase/rules-unit-testing 模組與模擬器互動 執行在本機的容器如果出現逾時或 ECONNREFUSED 錯誤,請仔細檢查模擬器是否確實正在執行。

強烈建議您使用新版 Node.js,以便使用 async/await 標記法。您想要測試的所有行為 涉及非同步函式,而測試模組的設計宗旨是讓 以 Promise 為基礎的程式碼。

v9 Rules 單元測試程式庫一律會感知模擬器, 您會很熟悉生產資源

您可使用 v9 模組匯入陳述式匯入程式庫。例如:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment
} from "@firebase/rules-unit-testing"

// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.

匯入後,實作單元測試涉及:

  • 透過對 initializeTestEnvironment 的呼叫,建立及設定 RulesTestEnvironment
  • 以便利的方式設定測試資料,而不觸發 Rules 方法可讓您暫時略過 RulesTestEnvironment.withSecurityRulesDisabled
  • 設定測試套件,並在掛鉤前後進行個別測試 清除測試資料和環境 (例如 RulesTestEnvironment.cleanup()) 或 RulesTestEnvironment.clearFirestore()
  • 使用 「RulesTestEnvironment.authenticatedContext」和 RulesTestEnvironment.unauthenticatedContext
,瞭解如何調查及移除這項存取權。

常用方法和公用程式函式

另請參閱 使用模組 API 的特定模擬器測試方法

initializeTestEnvironment() => RulesTestEnvironment

這個函式會初始化規則單元測試的測試環境。呼叫此項目 函式,用於測試設定。成功執行需要模擬器必須 備用資源

此函式接受選用物件定義 TestEnvironmentConfig, 包含專案 ID 和模擬器配置設定。

let testEnv = await initializeTestEnvironment({
  projectId: "demo-project-1234",
  firestore: {
    rules: fs.readFileSync("firestore.rules", "utf8"),
  },
});

RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext

這個方法會建立 RulesTestContext,其運作方式類似於經過驗證的 Authentication 位使用者。透過傳回的結構定義建立的要求會有模擬畫面 已附加 Authentication 個權杖。您可以選擇傳遞定義自訂宣告或覆寫 Authentication 權杖酬載的物件。

在測試中使用傳回的測試情境物件存取任何模擬器 設定的執行個體,包括使用 initializeTestEnvironment 設定的執行個體。

// Assuming a Firestore app and the Firestore emulator for this example
import { setDoc } from "firebase/firestore";

const alice = testEnv.authenticatedContext("alice", {  });
// Use the Firestore instance associated with this context
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

RulesTestEnvironment.unauthenticatedContext() => RulesTestContext

這個方法會建立 RulesTestContext,運作方式就像用戶端 未透過 Authentication 登入。透過傳回的結構定義建立的要求不會 已附加 Firebase 驗證權杖。

在測試中使用傳回的測試情境物件存取任何模擬器 設定的執行個體,包括使用 initializeTestEnvironment 設定的執行個體。

// Assuming a Cloud Storage app and the Storage emulator for this example
import { getStorage, ref, deleteObject } from "firebase/storage";

const alice = testEnv.unauthenticatedContext();

// Use the Cloud Storage instance associated with this context
const desertRef = ref(alice.storage(), 'images/desert.jpg');
await assertSucceeds(deleteObject(desertRef));

RulesTestEnvironment.withSecurityRulesDisabled()

利用情境模擬安全性規則,執行測試設定函式 已停用。

這個方法會採用回呼函式,該函式會採用 Security-Rules-bypassing 內容並傳回 Promise。承諾解析/拒絕後,系統就會銷毀這個內容。

RulesTestEnvironment.cleanup()

這個方法會刪除在測試環境中建立的所有 RulesTestContexts,並 這會清除基礎資源,以便順暢結束作業。

這個方法不會以任何方式變更模擬器的狀態。重設資料的方式 請使用應用程式模擬器專屬的清除資料方法,才能進行測試。

assertSucceeds(pr: Promise<any>)) => Promise<any>

這是測試案例公用程式函式。

這個函式會宣告提供的 Promise 包裝模擬器作業 會在沒有違反安全性規則的情況下解決。

await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

assertFails(pr: Promise<any>)) => Promise<any>

這是測試案例公用程式。

這個函式會宣告提供的 Promise 包裝模擬器作業 就會遭到拒絕,並顯示安全性規則。

await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });

Android Emulator 專用方法

另請參閱 常見的測試方法和模組函式使用模組化 API 的公用程式函式

Cloud Firestore

Cloud Firestore

RulesTestEnvironment.clearFirestore() => Promise<void>

這個方法會清除屬於 為 Firestore 模擬器設定的 projectId

RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;

這個方法會取得此測試結構定義的 Firestore 執行個體。傳回的 Firebase JS 用戶端 SDK 執行個體可與用戶端 SDK API (第 9 版模組) 搭配使用 或 v9 Compat)。

Realtime Database

Realtime Database

RulesTestEnvironment.clearDatabase() => Promise<void>

這個方法會清除屬於Realtime DatabaseRealtime Database 模擬器設定的 projectId

RulesTestContext.database(databaseURL?: Firestore.FirestoreSettings) => Firestore;

取得這個測試結構定義的 Realtime Database 例項。傳回的 Firebase JS Client SDK 例項可搭配用戶端 SDK API (模組化或命名空間,版本 9 以上) 使用。此方法會接受即時資料庫例項的網址。如果有指定,系統會傳回模擬版本 包含擷取自網址之參數的命名空間

Cloud Storage

Cloud Storage

RulesTestEnvironment.clearStorage() => Promise<void>

這個方法會清除 已為 Cloud Storage 模擬器設定 projectId

RulesTestContext.storage(bucketUrl?: string) => Firebase Storage;

這個方法會傳回設定以連線至模擬器的 Storage 執行個體。 此方法會接受 gs:// 至 Firebase Storage Bucket 的網址,以便進行測試。如果 會回傳 Cloud Storage 執行個體,該值區名稱的模擬版本。

使用 v8 JavaScript SDK 執行本機單元測試

選取產品即可查看 Firebase Test SDK 用於介面的方法 實際操作

Cloud Firestore

initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp

這個方法會傳回與專案對應的已初始化 Firebase 應用程式 選項中指定的 ID 和驗證變數。使用此功能建立應用程式 以特定使用者的身分通過驗證,以便用於測試。

firebase.initializeTestApp({
  projectId: "my-test-project",
  auth: { uid: "alice", email: "alice@example.com" }
});

initializeAdminApp({ projectId: string }) => FirebaseApp

這個方法會傳回已初始化的管理員 Firebase 應用程式。執行讀取和寫入作業時,這個應用程式會略過安全性規則。使用此功能建立應用程式 須以管理員的身分通過驗證,才能設定測試狀態。

firebase.initializeAdminApp({ projectId: "my-test-project" });
    

apps() => [FirebaseApp] 這個方法會傳回目前已初始化的所有測試和管理應用程式。您可以使用這項功能來清除測試期間或測試後的應用程式。

Promise.all(firebase.apps().map(app => app.delete()))

loadFirestoreRules({ projectId: string, rules: Object }) => Promise

這個方法會將規則傳送至本機執行的資料庫。它會接收以字串形式指定規則的物件。使用這個方法即可設定資料庫的規則。

firebase.loadFirestoreRules({
  projectId: "my-test-project",
  rules: fs.readFileSync("/path/to/firestore.rules", "utf8")
});
    

assertFails(pr: Promise) => Promise

這個方法會傳回在輸入成功時遭到拒絕的承諾,或 就會成功。使用此方法斷言資料庫是否讀取或 寫入失敗

firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
    

assertSucceeds(pr: Promise) => Promise

如果輸入成功,且 遭到拒絕。使用此方法斷言資料庫是否讀取或 寫入成功

firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
    

clearFirestoreData({ projectId: string }) => Promise

這個方法會清除叢集中特定專案的所有資料 執行本機運作的 Firestore 執行個體測試完成後,請使用這個方法進行清除。

firebase.clearFirestoreData({
  projectId: "my-test-project"
});
   

Realtime Database

Realtime Database

initializeTestApp({ databaseName: string, auth: Object }) => FirebaseApp

可用來建立以特定使用者身分驗證的應用程式,以在測試中使用。

傳回與資料庫名稱和驗證相對應的已初始化 Firebase 應用程式 變數覆寫。

firebase.initializeTestApp({
  databaseName: "my-database",
  auth: { uid: "alice" }
});

initializeAdminApp({ databaseName: string }) => FirebaseApp

請使用此項目建立以管理員身分通過驗證的應用程式,以便設定測試狀態。

傳回與資料庫名稱相對應的已初始化管理員 Firebase 應用程式 會在選項中指定。這個應用程式會在讀取及寫入時略過安全性規則 並將結果傳送至資料庫

firebase.initializeAdminApp({ databaseName: "my-database" });

loadDatabaseRules({ databaseName: string, rules: Object }) => Promise

請使用此項目設定資料庫規則。

將規則傳送至本機執行的資料庫。採用以下選項物件: 指出您的「databaseName」您的「規則」視為字串。

firebase
      .loadDatabaseRules({
        databaseName: "my-database",
        rules: "{'rules': {'.read': false, '.write': false}}"
      });

apps() => [FirebaseApp]

傳回所有目前初始化的測試和管理員應用程式。

用於在測試期間或測試後清理應用程式 (請注意已初始化的應用程式) ,以便阻止 JavaScript 退出):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

如果輸入內容成功並成功,系統會傳回拒絕的承諾。 輸入內容會遭到拒絕

您可以使用這個選項斷言資料庫讀取或寫入失敗:

firebase.assertFails(app.database().ref("secret").once("value"));

assertSucceeds(pr: Promise) => Promise

傳回在輸入成功時成功的承諾,如果輸入內容遭拒,就會遭到拒絕。

使用此方法斷言資料庫讀取或寫入成功:

firebase.assertSucceeds(app.database().ref("public").once("value"));

Cloud Storage

Cloud Storage

initializeTestApp({ storageBucket: string, auth: Object }) => FirebaseApp

可用來建立以特定使用者身分驗證的應用程式,以在測試中使用。

傳回與儲存空間值區名稱相對應的已初始化 Firebase 應用程式 和 auth 變數覆寫

firebase.initializeTestApp({
  storageBucket: "my-bucket",
  auth: { uid: "alice" }
});

initializeAdminApp({ storageBucket: string }) => FirebaseApp

您可以使用這個選項建立以管理員身分驗證的應用程式,以便設定測試狀態。

傳回已初始化的管理員 Firebase 應用程式,該應用程式與選項中指定的儲存空間值區名稱相符。這個應用程式會在讀取及讀取資料時略過安全性規則 寫入值區

firebase.initializeAdminApp({ storageBucket: "my-bucket" });

loadStorageRules({ storageBucket: string, rules: Object }) => Promise

您可以利用此項目來設定儲存空間值區的規則。

將規則傳送至本機代管的儲存空間值區。接收指定「storageBucket」和「rules」為字串的選項物件。

firebase
      .loadStorageRules({
        storageBucket: "my-bucket",
        rules: fs.readFileSync("/path/to/storage.rules", "utf8")
      });

apps() => [FirebaseApp]

傳回所有目前初始化的測試和管理員應用程式。

用於在測試期間或測試後清理應用程式 (請注意已初始化的應用程式) ,以便阻止 JavaScript 退出):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

如果輸入內容成功並成功,系統會傳回拒絕的承諾。 輸入內容會遭到拒絕

可用於斷言儲存值區讀取或寫入作業失敗:

firebase.assertFails(app.storage().ref("letters/private.doc").getMetadata());

assertSucceeds(pr: Promise) => Promise

會傳回輸入成功時成功的承諾,如果輸入成功則會遭到拒絕 輸入內容會遭到拒絕

您可以使用這個選項,斷言儲存空間值區讀取或寫入成功:

firebase.assertFails(app.storage().ref("images/cat.png").getMetadata());

JS SDK 第 8 版適用的 RUT 程式庫 API

選取產品,查看 Firebase Test SDK 用於與模擬器連結的方法。

Cloud Firestore

Cloud Firestore

initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp

這個方法會傳回與專案對應的已初始化 Firebase 應用程式 選項中指定的 ID 和驗證變數。使用此功能建立應用程式 以特定使用者的身分通過驗證,以便用於測試。

firebase.initializeTestApp({
  projectId: "my-test-project",
  auth: { uid: "alice", email: "alice@example.com" }
});

initializeAdminApp({ projectId: string }) => FirebaseApp

這個方法會傳回已初始化的管理員 Firebase 應用程式。執行讀取和寫入作業時,這個應用程式會略過安全性規則。使用此功能建立應用程式 須以管理員的身分通過驗證,才能設定測試狀態。

firebase.initializeAdminApp({ projectId: "my-test-project" });
    

apps() => [FirebaseApp] 這個方法會傳回目前已初始化的所有測試和管理應用程式。您可以使用這項功能來清除測試期間或測試後的應用程式。

Promise.all(firebase.apps().map(app => app.delete()))

loadFirestoreRules({ projectId: string, rules: Object }) => Promise

這個方法會將規則傳送至本機執行的資料庫。它會接收以字串形式指定規則的物件。使用這個方法即可設定資料庫的規則。

firebase.loadFirestoreRules({
  projectId: "my-test-project",
  rules: fs.readFileSync("/path/to/firestore.rules", "utf8")
});
    

assertFails(pr: Promise) => Promise

這個方法會傳回在輸入成功時遭到拒絕的承諾,或 就會成功。使用此方法斷言資料庫是否讀取或 寫入失敗

firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
    

assertSucceeds(pr: Promise) => Promise

如果輸入成功,且 遭到拒絕。使用此方法斷言資料庫是否讀取或 寫入成功

firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
    

clearFirestoreData({ projectId: string }) => Promise

這個方法會清除叢集中特定專案的所有資料 執行本機運作的 Firestore 執行個體測試完成後,請使用這個方法進行清除。

firebase.clearFirestoreData({
  projectId: "my-test-project"
});
   

Realtime Database

Realtime Database

initializeTestApp({ databaseName: string, auth: Object }) => FirebaseApp

可用來建立以特定使用者身分驗證的應用程式,以在測試中使用。

傳回與資料庫名稱和驗證相對應的已初始化 Firebase 應用程式 變數覆寫。

firebase.initializeTestApp({
  databaseName: "my-database",
  auth: { uid: "alice" }
});

initializeAdminApp({ databaseName: string }) => FirebaseApp

請使用此項目建立以管理員身分通過驗證的應用程式,以便設定測試狀態。

傳回與資料庫名稱相對應的已初始化管理員 Firebase 應用程式 會在選項中指定。這個應用程式會在讀取及寫入時略過安全性規則 並將結果傳送至資料庫

firebase.initializeAdminApp({ databaseName: "my-database" });

loadDatabaseRules({ databaseName: string, rules: Object }) => Promise

請使用此項目設定資料庫規則。

將規則傳送至本機執行的資料庫。採用以下選項物件: 指出您的「databaseName」您的「規則」視為字串。

firebase
      .loadDatabaseRules({
        databaseName: "my-database",
        rules: "{'rules': {'.read': false, '.write': false}}"
      });

apps() => [FirebaseApp]

傳回所有目前初始化的測試和管理員應用程式。

用於在測試期間或測試後清理應用程式 (請注意已初始化的應用程式) ,以便阻止 JavaScript 退出):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

如果輸入內容成功並成功,系統會傳回拒絕的承諾。 輸入內容會遭到拒絕

您可以使用這個選項斷言資料庫讀取或寫入失敗:

firebase.assertFails(app.database().ref("secret").once("value"));

assertSucceeds(pr: Promise) => Promise

傳回在輸入成功時成功的承諾,如果輸入內容遭拒,就會遭到拒絕。

使用此方法斷言資料庫讀取或寫入成功:

firebase.assertSucceeds(app.database().ref("public").once("value"));

Cloud Storage

Cloud Storage

initializeTestApp({ storageBucket: string, auth: Object }) => FirebaseApp

可用來建立以特定使用者身分驗證的應用程式,以在測試中使用。

傳回與儲存空間值區名稱相對應的已初始化 Firebase 應用程式 和 auth 變數覆寫

firebase.initializeTestApp({
  storageBucket: "my-bucket",
  auth: { uid: "alice" }
});

initializeAdminApp({ storageBucket: string }) => FirebaseApp

您可以使用這個選項建立以管理員身分驗證的應用程式,以便設定測試狀態。

傳回已初始化的管理員 Firebase 應用程式,該應用程式與選項中指定的儲存空間值區名稱相符。這個應用程式會在讀取及讀取資料時略過安全性規則 寫入值區

firebase.initializeAdminApp({ storageBucket: "my-bucket" });

loadStorageRules({ storageBucket: string, rules: Object }) => Promise

您可以利用此項目來設定儲存空間值區的規則。

將規則傳送至本機代管的儲存空間值區。接收指定「storageBucket」和「rules」為字串的選項物件。

firebase
      .loadStorageRules({
        storageBucket: "my-bucket",
        rules: fs.readFileSync("/path/to/storage.rules", "utf8")
      });

apps() => [FirebaseApp]

傳回所有目前初始化的測試和管理員應用程式。

用於在測試期間或測試後清理應用程式 (請注意已初始化的應用程式) ,以便阻止 JavaScript 退出):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

如果輸入內容成功並成功,系統會傳回拒絕的承諾。 輸入內容會遭到拒絕

可用於斷言儲存值區讀取或寫入作業失敗:

firebase.assertFails(app.storage().ref("letters/private.doc").getMetadata());

assertSucceeds(pr: Promise) => Promise

會傳回輸入成功時成功的承諾,如果輸入成功則會遭到拒絕 輸入內容會遭到拒絕

您可以使用這個選項,斷言儲存空間值區讀取或寫入成功:

firebase.assertFails(app.storage().ref("images/cat.png").getMetadata());