Files
int-layer/tests/README.md

4.6 KiB

Tests

This directory contains the test suite for the capa-de-integracion application.

Test Dependencies

  • pytest - Test framework
  • pytest-asyncio - Async test support
  • pytest-cov - Coverage reporting
  • pytest-env - Environment variable configuration (cleaner than manual setup)
  • pytest-recording - HTTP recording (configured but not used for gRPC Firestore)
  • inline-snapshot - Snapshot testing support

Running Tests

# Run all tests
uv run pytest

# Run specific test file
uv run pytest tests/services/test_firestore_service.py

# Run with coverage
uv run pytest --cov=capa_de_integracion

# Run with verbose output
uv run pytest -v

Firestore Service Tests

The Firestore service tests require the Firestore emulator to be running.

Prerequisites

  1. Start the Firestore Emulator:

    gcloud firestore emulators start --host-port=[::1]:8911
    

    Or if using Firebase CLI:

    firebase emulators:start --only firestore
    
  2. Configure Indexes (optional, for advanced queries): The firestore.indexes.json file defines composite indexes needed for some queries. The emulator should automatically apply these when started in the project directory.

Test Structure

  • test_firestore_service.py - Comprehensive tests for FirestoreService
    • TestSessionManagement - Conversation session CRUD operations
    • TestEntryManagement - Conversation entry operations
    • TestNotificationManagement - Notification operations
    • TestEdgeCases - Edge cases and error handling

Important Notes

Why No pytest-recording Cassettes?

While pytest-recording is configured in the project, cassettes are not generated for Firestore tests. This is because:

  • Firestore uses gRPC protocol, not HTTP
  • pytest-recording/vcrpy only supports HTTP requests
  • The Firestore Python client communicates via gRPC, which cannot be recorded by vcrpy

Solution: Tests run directly against the Firestore emulator. This provides:

  • Real integration testing with actual Firestore behavior
  • No mocking - tests verify actual data operations
  • Fast execution (emulator is local)
  • Requires emulator to be running

If you need offline/recorded tests, consider:

  1. Using the emulator's export/import feature for test data
  2. Implementing a mock FirestoreService for unit tests
  3. Using snapshot testing with inline-snapshot for assertions

Composite Index Requirements

Some tests require composite indexes (e.g., queries with both where and order_by):

  • test_get_session_by_phone_existing - Currently skipped
    • Requires index on: telefono (ASC) + lastModified (DESC)
    • To enable: Configure index in firestore.indexes.json and restart emulator

Environment Variables

Tests automatically configure environment variables via pytest-env plugin. Configuration is in pytest.ini:

[pytest]
env =
    FIRESTORE_EMULATOR_HOST=[::1]:8911
    GCP_PROJECT_ID=test-project
    GCP_LOCATION=us-central1
    GCP_FIRESTORE_DATABASE_ID=(default)
    RAG_ENDPOINT_URL=http://localhost:8000/rag
    REDIS_HOST=localhost
    REDIS_PORT=6379
    DLP_TEMPLATE_COMPLETE_FLOW=projects/test/dlpJobTriggers/test

These are automatically loaded before any test runs, ensuring consistent test environment setup.

Fixtures

emulator_settings

Session-scoped fixture providing Settings configured for emulator testing.

firestore_service

Function-scoped fixture providing a FirestoreService instance connected to the emulator. Automatically closes the service after each test.

clean_firestore

Function-scoped fixture providing a FirestoreService with cleaned collections before and after each test. Use this fixture to ensure test isolation.

Adding New Tests

When adding new Firestore tests:

  1. Use clean_firestore fixture for test isolation
  2. Use the actual model classes (ConversationSession, ConversationEntry, Notification)
  3. Use model creation methods (e.g., ConversationSession.create(), Notification.create())
  4. Assert on actual data structures, not mocked values
  5. Consider adding inline-snapshot assertions for complex data validation

Example:

async def test_new_feature(clean_firestore: FirestoreService) -> None:
    """Test description."""
    # Create test data
    session = await clean_firestore.create_session(
        session_id="test-id",
        user_id="user-123",
        telefono="+1234567890",
    )

    # Test the feature
    result = await clean_firestore.some_method(session.session_id)

    # Assert results
    assert result is not None
    assert result.some_field == "expected_value"