Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions backend/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
asyncio_mode = auto
addopts =
-v
--tb=short
--strict-markers
--disable-warnings

markers =
asyncio: mark test as async
117 changes: 117 additions & 0 deletions backend/tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Backend Unit Tests

Comprehensive unit tests for the Insurance Management Platform backend API.

## πŸ€– Generated by TestKraft

These tests were automatically generated by **TestKraft** - an AI-powered test generation platform that creates comprehensive, production-ready unit tests for backend applications.

## Test Coverage

### Core Module Tests
- **test_config.py** - Configuration settings, environment variables, validation
- **test_security.py** - JWT token creation, password hashing, verification

### Database Tests
- **test_session.py** - Database session management, async engine configuration

### API Tests
- **test_main.py** - FastAPI application, endpoints, CORS, middleware

### Model Tests
- **test_user.py** - User model, fields, relationships, validation
- **test_policy.py** - Policy model, PolicyType enum, constraints
- **test_claim.py** - Claim model, status handling, relationships
- **test_payment.py** - Payment model, transaction handling, status
- **test_models_init.py** - Model package exports and integration

## Test Strategy

All tests follow comprehensive testing principles:

βœ… **Boundary Value Analysis** - Testing edge cases, min/max values, empty/null inputs
βœ… **Equivalence Class Partitioning** - Representative test cases for each behavior class
βœ… **Actual Behavior Testing** - Tests verify what the code actually does
βœ… **Mocked Dependencies** - Database, external services properly mocked
βœ… **Error Conditions** - Exception handling and validation tested

## Running the Tests

### Run all tests
```bash
cd backend
pytest
```

### Run specific test file
```bash
pytest tests/app/core/test_security.py
```

### Run with coverage
```bash
pytest --cov=app --cov-report=html
```

### Run tests matching a pattern
```bash
pytest -k "test_user"
```

### Run verbose output
```bash
pytest -v
```

## Test Structure

```
tests/
β”œβ”€β”€ conftest.py # Shared fixtures and configuration
β”œβ”€β”€ app/
β”‚ β”œβ”€β”€ core/
β”‚ β”‚ β”œβ”€β”€ test_config.py
β”‚ β”‚ └── test_security.py
β”‚ β”œβ”€β”€ db/
β”‚ β”‚ └── test_session.py
β”‚ β”œβ”€β”€ models/
β”‚ β”‚ β”œβ”€β”€ test_user.py
β”‚ β”‚ β”œβ”€β”€ test_policy.py
β”‚ β”‚ β”œβ”€β”€ test_claim.py
β”‚ β”‚ β”œβ”€β”€ test_payment.py
β”‚ β”‚ └── test_models_init.py
β”‚ └── test_main.py
└── README.md
```

## Dependencies

Required packages (already in requirements.txt):
- pytest >= 8.1.1
- pytest-asyncio >= 0.23.5
- httpx >= 0.27.0

## Fixtures

**conftest.py** provides shared fixtures:
- `mock_settings` - Mock configuration settings
- `async_db_engine` - In-memory async database engine
- `async_db_session` - Async database session for testing

## Test Statistics

- **Total Test Files:** 10
- **Framework:** pytest with async support
- **Backend Files Tested:** 9 Python modules
- **Test Categories:** Config, Security, Database, API, Models

## Notes

- Tests use in-memory SQLite database for speed
- All async operations properly handled with pytest-asyncio
- Mocked external dependencies for isolation
- Comprehensive boundary value and edge case testing

---

πŸ€– **Generated by TestKraft** - AI-Powered Backend Test Generation
1 change: 1 addition & 0 deletions backend/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Tests package initialization
1 change: 1 addition & 0 deletions backend/tests/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# App tests package
1 change: 1 addition & 0 deletions backend/tests/app/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Core tests package
189 changes: 189 additions & 0 deletions backend/tests/app/core/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
"""
Unit tests for app.core.config module.

Tests the Settings configuration class with various scenarios including:
- Default values
- Environment variable loading
- Required fields validation
- Boundary value testing
"""
import pytest
from unittest.mock import patch, MagicMock
from pydantic import ValidationError


def test_settings_default_values():
"""Test Settings class with default values where applicable."""
from app.core.config import Settings

# Mock environment variables for required fields
with patch.dict('os.environ', {
'SECRET_KEY': 'test_secret_key_123456789',
'DATABASE_URL': 'postgresql://user:pass@localhost/db'
}):
settings = Settings()

# Test default values
assert settings.PROJECT_NAME == "Insurance Management Platform"
assert settings.API_V1_STR == "/api/v1"
assert settings.ACCESS_TOKEN_EXPIRE_MINUTES == 60 * 24 * 7 # 7 days
assert settings.CORS_ORIGINS == "http://localhost:3000"

# Test required fields are loaded
assert settings.SECRET_KEY == 'test_secret_key_123456789'
assert settings.DATABASE_URL == 'postgresql://user:pass@localhost/db'


def test_settings_custom_values():
"""Test Settings class with custom environment values."""
from app.core.config import Settings

custom_env = {
'PROJECT_NAME': 'Custom Insurance Platform',
'API_V1_STR': '/api/v2',
'SECRET_KEY': 'custom_secret_key',
'ACCESS_TOKEN_EXPIRE_MINUTES': '120',
'CORS_ORIGINS': 'http://example.com,http://another.com',
'DATABASE_URL': 'postgresql://custom:pass@db.example.com/insurance'
}

with patch.dict('os.environ', custom_env, clear=True):
settings = Settings()

assert settings.PROJECT_NAME == 'Custom Insurance Platform'
assert settings.API_V1_STR == '/api/v2'
assert settings.SECRET_KEY == 'custom_secret_key'
assert settings.ACCESS_TOKEN_EXPIRE_MINUTES == 120
assert settings.CORS_ORIGINS == 'http://example.com,http://another.com'
assert settings.DATABASE_URL == 'postgresql://custom:pass@db.example.com/insurance'


def test_settings_missing_required_secret_key():
"""Test Settings validation fails when SECRET_KEY is missing."""
from app.core.config import Settings

with patch.dict('os.environ', {
'DATABASE_URL': 'postgresql://user:pass@localhost/db'
}, clear=True):
with pytest.raises(ValidationError) as exc_info:
Settings()

# Verify SECRET_KEY is mentioned in the error
assert 'SECRET_KEY' in str(exc_info.value)


def test_settings_missing_required_database_url():
"""Test Settings validation fails when DATABASE_URL is missing."""
from app.core.config import Settings

with patch.dict('os.environ', {
'SECRET_KEY': 'test_secret_key'
}, clear=True):
with pytest.raises(ValidationError) as exc_info:
Settings()

# Verify DATABASE_URL is mentioned in the error
assert 'DATABASE_URL' in str(exc_info.value)


def test_settings_boundary_access_token_expire_minutes_zero():
"""Test ACCESS_TOKEN_EXPIRE_MINUTES with boundary value of zero."""
from app.core.config import Settings

with patch.dict('os.environ', {
'SECRET_KEY': 'test_secret',
'DATABASE_URL': 'postgresql://user:pass@localhost/db',
'ACCESS_TOKEN_EXPIRE_MINUTES': '0'
}):
settings = Settings()
assert settings.ACCESS_TOKEN_EXPIRE_MINUTES == 0


def test_settings_boundary_access_token_expire_minutes_large():
"""Test ACCESS_TOKEN_EXPIRE_MINUTES with large value."""
from app.core.config import Settings

with patch.dict('os.environ', {
'SECRET_KEY': 'test_secret',
'DATABASE_URL': 'postgresql://user:pass@localhost/db',
'ACCESS_TOKEN_EXPIRE_MINUTES': '525600' # 1 year in minutes
}):
settings = Settings()
assert settings.ACCESS_TOKEN_EXPIRE_MINUTES == 525600


def test_settings_empty_cors_origins():
"""Test CORS_ORIGINS with empty string."""
from app.core.config import Settings

with patch.dict('os.environ', {
'SECRET_KEY': 'test_secret',
'DATABASE_URL': 'postgresql://user:pass@localhost/db',
'CORS_ORIGINS': ''
}):
settings = Settings()
assert settings.CORS_ORIGINS == ''


def test_settings_multiple_cors_origins():
"""Test CORS_ORIGINS with multiple comma-separated values."""
from app.core.config import Settings

cors_value = 'http://localhost:3000,http://localhost:3001,https://example.com'
with patch.dict('os.environ', {
'SECRET_KEY': 'test_secret',
'DATABASE_URL': 'postgresql://user:pass@localhost/db',
'CORS_ORIGINS': cors_value
}):
settings = Settings()
assert settings.CORS_ORIGINS == cors_value


def test_settings_singleton_instance():
"""Test that the settings singleton instance is accessible."""
from app.core.config import settings

# Verify the singleton exists and has expected attributes
assert hasattr(settings, 'PROJECT_NAME')
assert hasattr(settings, 'SECRET_KEY')
assert hasattr(settings, 'DATABASE_URL')
assert hasattr(settings, 'ACCESS_TOKEN_EXPIRE_MINUTES')


def test_settings_extra_fields_ignored():
"""Test that extra fields in environment are ignored due to extra='ignore'."""
from app.core.config import Settings

with patch.dict('os.environ', {
'SECRET_KEY': 'test_secret',
'DATABASE_URL': 'postgresql://user:pass@localhost/db',
'UNKNOWN_FIELD': 'should_be_ignored',
'ANOTHER_EXTRA': 'also_ignored'
}):
settings = Settings()

# Should not raise an error, extra fields are ignored
assert not hasattr(settings, 'UNKNOWN_FIELD')
assert not hasattr(settings, 'ANOTHER_EXTRA')


def test_settings_api_v1_str_variations():
"""Test API_V1_STR with different valid path formats."""
from app.core.config import Settings

test_cases = [
'/api/v1',
'/api/v2',
'/v1',
'',
'/custom/api/path'
]

for api_str in test_cases:
with patch.dict('os.environ', {
'SECRET_KEY': 'test_secret',
'DATABASE_URL': 'postgresql://user:pass@localhost/db',
'API_V1_STR': api_str
}):
settings = Settings()
assert settings.API_V1_STR == api_str
Loading