Skip to content

Testing with UUID-Forge

Learn how to leverage deterministic UUIDs for more effective testing strategies.

Overview

Deterministic UUID generation provides significant advantages for testing by making UUIDs predictable and reproducible. This enables more reliable tests, easier debugging, and better test data management.

Benefits for Testing

Predictable Test Data

from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID

def test_user_creation():
    """Test with predictable UUIDs"""
    config = IDConfig(namespace=Namespace("test.example.com"), salt="test-v1")
    generator = UUIDGenerator(config)

    # Always generates the same UUID for same input
    user_id = generator.generate("user", email="test@example.com")

    # Test assertions can verify UUID properties
    assert isinstance(user_id, UUID)
    assert str(user_id)  # Can convert to string

    # Deterministic - same input always produces same UUID
    user_id_2 = generator.generate("user", email="test@example.com")
    assert user_id == user_id_2

Reproducible Test Scenarios

import pytest
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID

class TestOrderProcessing:
    def setUp(self):
        user_config = IDConfig(namespace=Namespace("test.example.com/users"), salt="test-v1")
        order_config = IDConfig(namespace=Namespace("test.example.com/orders"), salt="test-v1")

        self.user_gen = UUIDGenerator(user_config)
        self.order_gen = UUIDGenerator(order_config)

    def test_order_workflow(self):
        """Test complete order workflow with predictable UUIDs"""
        # Same UUIDs generated every test run
        user_id = self.user_gen.generate("user", email="customer@test.com")

        order_id = self.order_gen.generate(
            "order",
            user_id=str(user_id),
            item1="product1",
            item2="product2",
            timestamp="2024-01-15T10:00:00Z"
        )

        # Test can rely on deterministic UUID generation
        # Same inputs always produce same UUIDs
        expected_user_id = self.user_gen.generate("user", email="customer@test.com")
        assert user_id == expected_user_id

        expected_order_id = self.order_gen.generate(
            "order",
            user_id=str(user_id),
            item1="product1",
            item2="product2",
            timestamp="2024-01-15T10:00:00Z"
        )
        assert order_id == expected_order_id

Test Data Management

Fixture-Based Testing

import pytest
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID
from typing import Dict

@pytest.fixture
def test_generators() -> Dict[str, UUIDGenerator]:
    """Provide test UUID generators"""
    return {
        "users": UUIDGenerator(
            IDConfig(namespace=Namespace("test.example.com/users"), salt="test-v1")
        ),
        "orders": UUIDGenerator(
            IDConfig(namespace=Namespace("test.example.com/orders"), salt="test-v1")
        ),
        "products": UUIDGenerator(
            IDConfig(namespace=Namespace("test.example.com/products"), salt="test-v1")
        ),
    }

@pytest.fixture
def test_users(test_generators):
    """Generate test user data with deterministic UUIDs"""
    users = [
        {"email": "user1@test.com", "name": "User One", "region": "us"},
        {"email": "user2@test.com", "name": "User Two", "region": "eu"},
        {"email": "user3@test.com", "name": "User Three", "region": "asia"},
    ]

    for user in users:
        user["id"] = test_generators["users"].generate(
            "user",
            email=user["email"],
            region=user["region"]
        )

    return users

def test_user_processing(test_users):
    """Test using predictable user data"""
    assert len(test_users) == 3
    assert all(isinstance(user["id"], UUID) for user in test_users)

    # UUIDs are deterministic - same every test run
    first_user_id = test_users[0]["id"]
    assert isinstance(first_user_id, UUID)

    # All users have unique UUIDs (different inputs)
    user_ids = [user["id"] for user in test_users]
    assert len(set(user_ids)) == len(user_ids)

Database Testing

import pytest
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID

class TestDatabaseOperations:
    def setUp(self):
        user_config = IDConfig(namespace=Namespace("test.example.com/users"), salt="test-v1")
        self.user_gen = UUIDGenerator(user_config)
        self.setup_test_database()

    def test_user_crud_operations(self):
        """Test CRUD operations with deterministic UUIDs"""
        user_email = "dbtest@example.com"
        user_id = self.user_gen.generate("user", email=user_email)

        # Create
        self.db.create_user(user_id, user_email, "Test User")

        # Read - can regenerate UUID to lookup
        stored_user = self.db.get_user(user_id)
        assert stored_user["id"] == user_id
        assert stored_user["email"] == user_email

        # Can also regenerate UUID for lookup without storing it
        lookup_id = self.user_gen.generate("user", email=user_email)
        assert lookup_id == user_id
        stored_user_2 = self.db.get_user(lookup_id)
        assert stored_user_2["email"] == user_email

        # Update
        self.db.update_user(user_id, {"name": "Updated Name"})
        updated_user = self.db.get_user(user_id)
        assert updated_user["name"] == "Updated Name"

        # Delete
        self.db.delete_user(user_id)
        assert self.db.get_user(user_id) is None

    def test_relationship_integrity(self):
        """Test foreign key relationships"""
        user_id = self.user_gen.generate("user", email="parent@test.com")

        order_config = IDConfig(namespace=Namespace("test.example.com/orders"), salt="test-v1")
        order_gen = UUIDGenerator(order_config)

        # Create parent record
        self.db.create_user(user_id, "parent@test.com", "Parent User")

        # Create child record with deterministic UUID
        order_id = order_gen.generate(
            "order",
            user_email="parent@test.com",
            total=100.00
        )
        self.db.create_order(order_id, user_id, 100.00)

        # Verify relationship
        user_orders = self.db.get_user_orders(user_id)
        assert len(user_orders) == 1
        assert user_orders[0]["id"] == order_id

Integration Testing

Multi-Service Testing

from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID

class TestMicroservicesIntegration:
    def setUp(self):
        self.user_service = UserService()
        self.order_service = OrderService()
        self.notification_service = NotificationService()

        # All services use same UUID configuration for users
        user_config = IDConfig(
            namespace=Namespace("test.example.com/users"),
            salt="integration-test-v1"
        )
        self.user_gen = UUIDGenerator(user_config)

    def test_cross_service_workflow(self):
        """Test workflow spanning multiple services"""
        user_email = "integration@test.com"
        user_id = self.user_gen.generate("user", email=user_email)

        # Step 1: Create user
        user = self.user_service.create_user(user_email, "Test User")
        assert user["id"] == user_id

        # Step 2: Create order (should reference same user ID)
        # Order service can regenerate user UUID from email
        order = self.order_service.create_order(user_email, ["item1", "item2"])
        assert order["user_id"] == user_id

        # Step 3: Send notification (should reference same user ID)
        # Notification service can also regenerate user UUID
        notification = self.notification_service.send_order_confirmation(
            user_email, order["id"]
        )
        assert notification["user_id"] == user_id

        # All services independently generated the same user ID from the email
        assert user["id"] == order["user_id"] == notification["user_id"]

        # Verify we can regenerate the same UUID
        regenerated_id = self.user_gen.generate("user", email=user_email)
        assert regenerated_id == user_id

API Testing

import requests
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID

class TestAPIEndpoints:
    def setUp(self):
        self.base_url = "http://localhost:8000/api"
        user_config = IDConfig(
            namespace=Namespace("test.example.com/users"),
            salt="api-test-v1"
        )
        self.user_gen = UUIDGenerator(user_config)

    def test_user_api_endpoints(self):
        """Test user API with predictable UUIDs"""
        user_email = "apitest@example.com"
        expected_user_id = self.user_gen.generate("user", email=user_email)

        # POST /users - Create user
        create_response = requests.post(
            f"{self.base_url}/users",
            json={"email": user_email, "name": "API Test User"}
        )
        assert create_response.status_code == 201
        created_user = create_response.json()
        assert created_user["id"] == expected_user_id

        # GET /users/{id} - Retrieve user
        get_response = requests.get(f"{self.base_url}/users/{expected_user_id}")
        assert get_response.status_code == 200
        retrieved_user = get_response.json()
        assert retrieved_user["id"] == expected_user_id
        assert retrieved_user["email"] == user_email

        # PUT /users/{id} - Update user
        update_response = requests.put(
            f"{self.base_url}/users/{expected_user_id}",
            json={"name": "Updated API User"}
        )
        assert update_response.status_code == 200

        # DELETE /users/{id} - Delete user
        delete_response = requests.delete(f"{self.base_url}/users/{expected_user_id}")
        assert delete_response.status_code == 204

Property-Based Testing

Hypothesis Integration

from hypothesis import given, strategies as st
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID

class TestUUIDProperties:
    def setUp(self):
        config = IDConfig(namespace=Namespace("test.example.com"), salt="property-test-v1")
        self.generator = UUIDGenerator(config)

    @given(st.text(min_size=1))
    def test_uuid_type_property(self, input_text):
        """Property: All generated UUIDs are valid UUID objects"""
        uuid_result = self.generator.generate("entity", value=input_text)

        # Should be a UUID object
        assert isinstance(uuid_result, UUID)

        # Can convert to string
        uuid_str = str(uuid_result)
        assert len(uuid_str) == 36
        assert uuid_str.count("-") == 4

    @given(st.text(min_size=1))
    def test_determinism_property(self, input_text):
        """Property: Same input always produces same UUID"""
        uuid1 = self.generator.generate("entity", value=input_text)
        uuid2 = self.generator.generate("entity", value=input_text)

        assert uuid1 == uuid2
        assert isinstance(uuid1, UUID)

    @given(st.lists(st.text(min_size=1), min_size=2, unique=True))
    def test_uniqueness_property(self, input_list):
        """Property: Different inputs produce different UUIDs"""
        uuids = [
            self.generator.generate("entity", value=input_text)
            for input_text in input_list
        ]

        # All UUIDs should be unique
        assert len(set(uuids)) == len(uuids)
        assert all(isinstance(u, UUID) for u in uuids)

Performance Testing

Benchmark Testing

import time
from uuid_forge import UUIDGenerator, IDConfig, Namespace

class TestPerformance:
    def setUp(self):
        config = IDConfig(namespace=Namespace("test.example.com"), salt="perf-test-v1")
        self.generator = UUIDGenerator(config)
        self.test_data = [f"user{i}@test.com" for i in range(1000)]

    def test_single_generation_performance(self):
        """Test single UUID generation performance"""
        start_time = time.time()

        uuid_result = self.generator.generate("user", email="performance@test.com")

        end_time = time.time()
        generation_time = end_time - start_time

        # Should generate UUID very quickly
        assert generation_time < 0.01  # Under 10ms
        assert isinstance(uuid_result, UUID)

    def test_batch_generation_performance(self):
        """Test batch UUID generation performance"""
        start_time = time.time()

        uuids = [
            self.generator.generate("user", email=email)
            for email in self.test_data
        ]

        end_time = time.time()
        total_time = end_time - start_time

        # Should generate 1000 UUIDs quickly
        assert total_time < 1.0  # Under 1 second
        assert len(uuids) == 1000
        assert len(set(uuids)) == 1000  # All unique (different emails)

    def test_memory_usage(self):
        """Test memory usage during generation"""
        import psutil
        import os

        process = psutil.Process(os.getpid())
        initial_memory = process.memory_info().rss

        # Generate many UUIDs
        large_test_data = [f"user{i}@test.com" for i in range(10000)]
        uuids = [
            self.generator.generate("user", email=email)
            for email in large_test_data
        ]

        final_memory = process.memory_info().rss
        memory_increase = final_memory - initial_memory

        # Memory increase should be reasonable (less than 10MB)
        assert memory_increase < 10 * 1024 * 1024
        assert len(uuids) == 10000

Mock and Stub Testing

Deterministic Mocking

from unittest.mock import patch
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID

class TestWithMocking:
    def setUp(self):
        config = IDConfig(namespace=Namespace("test.example.com"), salt="mock-test-v1")
        self.test_generator = UUIDGenerator(config)

    @patch('external_service.get_user_id')
    def test_external_service_integration(self, mock_get_user_id):
        """Test integration with external service using predictable UUIDs"""
        test_email = "mocktest@example.com"
        expected_uuid = self.test_generator.generate("user", email=test_email)

        # Mock external service to return deterministic UUID
        mock_get_user_id.return_value = expected_uuid

        # Test our service
        result = our_service.process_user(test_email)

        # Verify mock was called correctly
        mock_get_user_id.assert_called_once_with(test_email)
        assert result["user_id"] == expected_uuid

    def test_time_dependent_operations(self):
        """Test operations that depend on time using fixed timestamps"""
        fixed_timestamp = "2024-01-15T10:00:00Z"

        with patch('datetime.datetime') as mock_datetime:
            mock_datetime.utcnow.return_value.isoformat.return_value = fixed_timestamp

            # Generate UUID with deterministic timestamp
            uuid_result = self.test_generator.generate(
                "event",
                user_email="timetest@example.com",
                timestamp=fixed_timestamp
            )

            # UUID is deterministic because timestamp is fixed
            expected_uuid = self.test_generator.generate(
                "event",
                user_email="timetest@example.com",
                timestamp=fixed_timestamp
            )
            assert uuid_result == expected_uuid

Test Environment Management

Environment-Specific Testing

import os
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID

class TestEnvironmentConfiguration:
    def test_development_environment(self):
        """Test development environment configuration"""
        os.environ["ENVIRONMENT"] = "development"
        os.environ["UUID_NAMESPACE_DOMAIN"] = "dev.example.com"

        config = IDConfig(
            namespace=Namespace(os.environ["UUID_NAMESPACE_DOMAIN"]),
            salt=f"{os.environ['ENVIRONMENT']}-v1"
        )
        generator = UUIDGenerator(config)

        dev_uuid = generator.generate("user", email="devtest@example.com")

        # Development environment generates consistent UUIDs
        assert isinstance(dev_uuid, UUID)

        # Can regenerate same UUID
        dev_uuid_2 = generator.generate("user", email="devtest@example.com")
        assert dev_uuid == dev_uuid_2

    def test_production_environment(self):
        """Test production environment configuration"""
        os.environ["ENVIRONMENT"] = "production"
        os.environ["UUID_NAMESPACE_DOMAIN"] = "prod.example.com"

        config = IDConfig(
            namespace=Namespace(os.environ["UUID_NAMESPACE_DOMAIN"]),
            salt=f"{os.environ['ENVIRONMENT']}-v1"
        )
        generator = UUIDGenerator(config)

        prod_uuid = generator.generate("user", email="prodtest@example.com")

        # Production environment uses different namespace
        # Different namespace/salt = different UUIDs even with same input
        assert isinstance(prod_uuid, UUID)

        # Verify it's different from dev (different namespace)
        dev_config = IDConfig(
            namespace=Namespace("dev.example.com"),
            salt="development-v1"
        )
        dev_generator = UUIDGenerator(dev_config)
        dev_uuid = dev_generator.generate("user", email="prodtest@example.com")
        assert prod_uuid != dev_uuid  # Different environments = different UUIDs

    def tearDown(self):
        """Clean up environment variables"""
        for var in ["ENVIRONMENT", "UUID_NAMESPACE_DOMAIN"]:
            if var in os.environ:
                del os.environ[var]

Continuous Integration Testing

CI/CD Pipeline Testing

# .github/workflows/test.yml
name: Test Suite
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: "3.11"

      - name: Install dependencies
        run: |
          pip install uv
          uv sync --dev

      - name: Run deterministic tests
        run: |
          # Run tests multiple times to verify determinism
          uv run pytest tests/test_deterministic.py
          uv run pytest tests/test_deterministic.py
          uv run pytest tests/test_deterministic.py

      - name: Run integration tests
        run: uv run pytest tests/test_integration.py

      - name: Run performance tests
        run: uv run pytest tests/test_performance.py

Next Steps