Closed rommik closed 1 month ago
Hi @rommik! I used an emulator for local tests: docker-compose:
# ...
firestore_emulator:
image: mtlynch/firestore-emulator:latest
environment:
- FIRESTORE_PROJECT_ID=project-name
- PORT=8200
ports:
- 8200:8200
# ...
def setup_remote_db(project_id: str):
firebase_app = firebase_admin.initialize_app(
firebase_admin.credentials.ApplicationDefault(),
{'projectId': project_id},
)
client = firebase_admin.firestore.client(firebase_app)
db.connect(client=client)
def setup_emulated_db(
project: str = 'dummy',
host: str = "0.0.0.0",
port: int = 8200,
) -> None:
os.environ["FIRESTORE_EMULATOR_HOST"] = f"{host}:{port}"
os.environ["FIRESTORE_EMULATOR_HOST_PATH"] = f"{host}:{port}/firestore"
credentials = Mock(spec=google.auth.credentials.Credentials)
client = google.cloud.firestore.Client(project=project, credentials=credentials)
db.connect(client=client)
def clean_emulated_db(
project: str = 'dummy',
host: str = "0.0.0.0",
port: int = 8200,
) -> None:
requests.delete(f"http://{host}:{port}/emulator/v1/projects/{project}/databases/(default)/documents")
@pytest.fixture(autouse=True, scope='session')
def setup_test_db():
"""Setup the database connection before the first test case."""
setup_emulated_db(
project=settings.FIRESTORE_EMULATOR_PROJECT,
host=settings.FIRESTORE_EMULATOR_HOST,
port=settings.FIRESTORE_EMULATOR_PORT,
)
yield
@pytest.fixture(autouse=True, scope='session')
def wait_for_emulator():
"""Wait for the database to be ready before each test case."""
logger.info('Waiting for firestore emulator to be ready...')
for _ in range(10):
try:
requests.get('http://{}:{}'.format(
settings.FIRESTORE_EMULATOR_HOST,
settings.FIRESTORE_EMULATOR_PORT,
))
logger.info('Firestore emulator is ready.')
return
except requests.exceptions.ConnectionError:
logger.info('Emulator is not ready yet...')
sleep(1)
raise Exception('Emulator is not ready')
@pytest.fixture(autouse=True, scope='session')
def clean_db_before_first_testcase() -> Generator[None, None, None]:
assert isinstance(settings, FirestoreEmulatorSettings)
clean_emulated_db(
settings.FIRESTORE_EMULATOR_PROJECT,
settings.FIRESTORE_EMULATOR_HOST,
settings.FIRESTORE_EMULATOR_PORT,
)
yield
@pytest.fixture(autouse=True, scope='class')
def clean_db_after_testcase() -> Generator[None, None, None]:
yield
assert isinstance(settings, FirestoreEmulatorSettings)
clean_emulated_db(
settings.FIRESTORE_EMULATOR_PROJECT,
settings.FIRESTORE_EMULATOR_HOST,
settings.FIRESTORE_EMULATOR_PORT,
)
class FirestoreEmulatorSettings(MyBasePydanticSettings):
FIRESTORE_EMULATOR_HOST: str = '0.0.0.0'
FIRESTORE_EMULATOR_PORT: int = 8200
FIRESTORE_EMULATOR_PROJECT: str = 'my-project-name'
hi @ADR-007 thanks for your reply. Yeah, running Firestore in docker is an option too. I should have mentioned it. It complicates my CI/CD, but it's not a show-stopper. Thanks for the code you provided.
Hello FireO,
First of all thank you for this awesome tool. I've been using it for a few days and love how simple and intuitive it is.
I've tried to find a working example online, but without luck. I hope the community here can point me to the right answer.
what are the best practices or recommendations when testing (with "pytest") code that depends on FireO?
In My initial attempt, I tried to mock Firestore with "MockFirestore" and leave the rest as is. Unfortunately, any create/update operations fail with
AttributeError: 'DocumentReference' object has no attribute 'path'. Did you mean: '_path'?
it seems MockFirestore doesn't faithfully implement some internals forfirebase_admin.firestore
Is there a better way?
Thanks.