如何在集成测试中重置 Firestore 模拟器

Posted

技术标签:

【中文标题】如何在集成测试中重置 Firestore 模拟器【英文标题】:How to reset firestore emulator in integration test 【发布时间】:2021-03-29 00:16:39 【问题描述】:

我正在使用 firestore 模拟器在颤振和飞镖中运行我的集成测试。首先,我使用如下数据启动 Firestore 模拟器:firebase emulators:start --import=./dir.

然后我启动一个 android 模拟器并启动我想在 android 模拟器上测试的应用程序。该应用程序配置为使用 Firestore 模拟器。然后我运行了一系列测试,所有测试都写入了 Firestore 模拟器。

但是在每次测试开始时,我希望将数据重置为我第一次启动模拟器时的状态。所以例如如果测试按此顺序执行:

测试 A 测试 B 测试C

我不想在执行测试 B 和 C 时创建数据,测试 A 存在于数据库中。我可以终止 firestore 模拟器并在每次测试开始时重新启动它。但这会使我的测试慢很多。

您知道一种重置数据的方法吗,它存在于 firebase 模拟器中?

【问题讨论】:

我认为不可能回到初始状态,您可以做的是删除所有数据然后重新导入,这样行吗?不确定这是否会比再次运行它更快终止并重新启动模拟器。 我遇到了同样的问题,我正在寻找一种解决方案来自动重置模拟器套件的相同部分(RTDB、Firestore 和身份验证)。如果您只想拥有一个干净的 Firestore,也许您可​​以创建一个 Firebase 函数来监听事件(例如,Firestore 中的特定写入事件或删除用户),然后删除 Firestore 的所有内容。 【参考方案1】:

当您说要“重置数据”时,我假设您指的是 Firestore。

根据https://firebase.google.com/docs/emulator-suite/install_and_configure#use_the_emulator_hub_rest_api 的文档

import fetch from 'node-fetch';

import firebaseConfig from '../../../firebase.json';
const hubEmulatorPort = firebaseConfig.emulators.hub.port;
const firestoreEmulatorPort = firebaseConfig.emulators.firestore.port;

async function clearDb() 
  const response = await fetch(
    `http://localhost:$firestoreEmulatorPort/emulator/v1/projects/$process.env.PROJECT_ID/databases/(default)/documents`,
    
      method: 'DELETE',
    
  );
  if (response.status !== 200) 
    throw new Error('Trouble clearing Emulator: ' + (await response.text()));
  


async function populateDb(data) 
  // Logic for adding in any data you want in the db
  // before each test run


async function enableBackgroundTriggers() 
  const response = await fetch(`http://localhost:$hubEmulatorPort/functions/enableBackgroundTriggers`, 
    method: 'PUT',
  );
  if (response.status !== 200) 
    throw new Error('Trouble enabling database triggers in emulator: ' + (await response.text()));
  


async function disableBackgroundTriggers() 
  const response = await fetch(`http://localhost:$hubEmulatorPort/functions/disableBackgroundTriggers`, 
    method: 'PUT',
  );
  if (response.status !== 200) 
    throw new Error('Trouble disabling database triggers in emulator: ' + (await response.text()));
  


async function resetDb(data) 
  await disableBackgroundTriggers();
  await clearDb();
  await populateDb(data);
  await enableBackgroundTriggers();


export  resetDb ;

我找不到清除数据库的来源,但 clearDb 中的 RESTful 调用可以满足您的需求。

在清除或填充数据库之前禁用触发器很重要,以防您的 firestore 触发器以您的测试不期望的方式修改数据。我通过将完整的 DB 状态传递给 populateDb 方法来编写测试,然后在运行测试之前重新启用触发器,以便我可以测试所述触发器。如果您没有运行任何 Firestore 触发器,那么仅 clearDb 调用就足以满足您的目的。

我的测试都在我的 beforeEach 挂钩中开玩笑地调用了 resetDb(),以确保每个测试的干净运行。我建议将此添加到您最喜欢的测试 API 公开的任何类似“beforeEach”的钩子中。

如果您的测试执行诸如在 Firebase 身份验证中创建用户之类的操作,则您必须找到另一种方法在测试运行之间清除它们。

如果有人可以找到有关如何清除 Firebase Emulator Suite 中其他模拟器的文档,请将其放入 cmets。我目前正在尝试找到一种清除身份验证模拟器的方法,这实际上就是我发现这个问题的方式。

祝你好运!

【讨论】:

以上是关于如何在集成测试中重置 Firestore 模拟器的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Dart VM / Dart 集成测试访问 Firebase Firestore?

Zend Framework 1 - 如何在功能集成测试中重置视图数据,而不是会话数据?

如何将 Google Cloud Firestore 本地模拟器用于 python 和测试目的

如何重置 kafka 以将其集成到 JUnit 测试过程中?

如何在模拟器中重置钥匙串?

如何在每次测试之前重置 Jest 模拟函数调用计数