使用实时数据库模拟器测试安全规则

实时数据库模拟器旨在让您更轻松地编写单元测试,以便检查数据库安全规则的表现。

当模拟器启动时,系统将出于安全考虑而“开放”您的数据库(即允许所有读取和写入操作)。您可以使用 Firebase Test SDK 模块更改单元测试框架中的安全规则(参见下文)。

模拟器和生产数据库的区别

  1. 您不必明确地创建数据库实例。模拟器会自动创建任何所访问的数据库实例。
  2. 每个新数据库在启动时都使用开放规则,因此任何用户都可以对任何路径执行读取或写入操作。
  3. 每个模拟数据库都适用 Spark 方案限制和配额(最需要注意的是,这会将每个实例的并发连接限制为 100 个)。
  4. 任何数据库都将接受字符串 "owner" 作为管理员身份验证令牌。
    1. 如果您想以管理员身份使用 REST API,请添加标头
      Authorization: Bearer owner
    2. 您可以通过此方法使用 curl 设置规则。假设您的规则位于 database.rules.json 文件中,则可以采用如下设置:
      curl -X PUT -H 'Authorization: Bearer owner' --data @database.rules.json http://localhost:9000/.settings/rules.json?ns=<name>
  5. 数据库模拟器不会与其他 Firebase 产品进行有效互动。请注意,标准的 Firebase 身份验证流程将无法进行。不过,我们在 Firebase Test SDK 测试模块中提供了 initializeTestApp() 方法,该方法接受 auth 字段。使用此方法创建的 Firebase 句柄的行为将如同它已经以您提供的任何实体身份成功通过身份验证一样。如果您传入 null,该句柄的行为将与未经身份验证的用户相同(例如,auth != null 规则将失败)。

安装模拟器

如需安装实时数据库模拟器,请使用 Firebase CLI 并运行下面的命令:

firebase setup:emulators:database

运行模拟器

使用以下命令启动模拟器。模拟器将一直运行,直到您终止相应进程为止:

firebase emulators:start --only database

请注意,实时数据库模拟器需要 Java 8 或更高版本。

在许多情况下,您需要启动模拟器,运行测试套件,然后在测试运行后关闭模拟器。您可以使用 emulators:exec 命令轻松完成这些操作:

firebase emulators:exec --only database "./my-test-script.sh"

模拟器启动后将尝试在默认端口 (9000) 上运行。您可以通过修改 firebase.json 文件的 "emulators" 部分来更改模拟器端口:

{
  // ...
  "emulators": {
    "database": {
      "port": "YOUR_PORT"
    }
  }
}

与模拟器进行互动

普通的 Firebase 实时数据库实例可通过 firebaseio.com 的子网域访问,您可以按如下所示访问 REST API:

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

模拟器在本地运行,并可通过 localhost:9000 访问。如需与特定数据库实例互动,您必须使用查询参数指定数据库名称。

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

我们提供了 @firebase/testing 模块,以便让您更轻松地使用 Firebase SDK 与模拟器互动。通过 @firebase/testing 模块,您可以与实时数据库模拟器在本地运行的版本互动。如果您遇到超时或 ECONNREFUSED 错误,请仔细检查模拟器是否正在运行。

我们强烈建议使用最新版本的 Node.js,以便您能够使用 async/await 表示法。几乎所有您可能希望测试的行为都涉及异步函数,并且测试模块设计为与基于 Promise 的代码配合使用。

该模块提供了以下方法:

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

使用此方法可创建以特定用户身份通过身份验证的应用,以用于测试。

此方法会返回一个初始化的 Firebase 应用,该应用与选项中指定的数据库名称和 auth 变量替换值相对应。请注意,此方法不使用 databaseURL,因为它并非针对远程服务器运行。

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

initializeAdminApp({ databaseName: }) => FirebaseApp

使用此方法可创建以管理员身份通过身份验证的应用,以设置测试状态。

此方法会返回一个初始化的 Firebase 管理应用,该应用与选项中指定的数据库名称相对应。在从数据库读取数据和向数据库写入数据时,该应用会绕过安全规则。

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

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

使用此方法可设置数据库的规则。

此方法可以将规则发送到本地运行的数据库,它接受一个将“databaseName”和“rules”表达为字符串的选项对象。

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

返回一个在输入成功时被拒并在输入被拒时成功的 promise。

使用此方法判断数据库读取或写入失败:

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

assertSucceeds(pr: Promise) => Promise

返回一个在输入成功时成功并在输入被拒时被拒的 promise。

使用此方法判断数据库读取或写入成功:

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

生成测试报告

运行一系列测试后,您可以访问测试范围报告,其中显示了每条安全规则的评估结果。 如需获取该报告,请在模拟器运行时查询其上的公开端点。如需查看适合浏览器的版本,请使用以下网址:

http://localhost:9000/.inspect/coverage?ns=<database_name>

此报告会将您的规则分解为表达式和子表达式,您可以将鼠标悬停在相应表达式上以了解更多信息(包括执行的次数和返回的值)。如需这些数据的原始 JSON 版本,请在查询中使用以下网址:

http://localhost:9000/.inspect/coverage.json?ns=<database_name>

快速入门

如果您只需要运行一个极为简单的示例,请尝试使用 JavaScript 快速入门