refactor: split monolithic app.py into modular Flask application with factory pattern

- Created app/ package with 6 modules:
  - __init__.py: Application factory (create_app function)
  - routes.py: All route handlers (473 lines)
  - models.py: Data persistence layer (41 lines)
  - validators.py: Input validation functions (48 lines)
  - email_service.py: Email sending functions (85 lines)
  - utils.py: Utility functions (30 lines)

- Implemented Flask application factory pattern
- Created run.py as minimal entry point
- Updated all test imports to use new module structure
- Fixed template/static folder paths for package structure

- All 102 tests passing
- Improved maintainability with clear separation of concerns
- Follows Flask best practices for scalable applications
This commit is contained in:
2025-12-27 22:36:05 +01:00
parent 733ee756c7
commit f1d8bae6a1
18 changed files with 1254 additions and 229 deletions
+8 -17
View File
@@ -3,16 +3,15 @@ Tests for HR email notifications functionality.
"""
import pytest
from unittest.mock import patch, MagicMock
from app import send_hr_notification
from app.email_service import send_hr_notification
class TestHRNotifications:
"""Test HR notification email functionality."""
def test_hr_notification_sent_on_submission(self, client, create_test_application, mock_mail):
def test_hr_notification_sent_on_submission(self, app, client, create_test_application, mock_mail):
"""Test that HR receives email when application is submitted."""
# Set HR_EMAIL in config
from app import app
app.config['HR_EMAIL'] = 'hr@example.com'
app.config['APPLICATION_URL_BASE'] = 'http://localhost:5000'
@@ -59,11 +58,10 @@ class TestHRNotifications:
assert f'/application/{session_id}/' in hr_email.body
def test_hr_notification_not_sent_when_hr_email_not_configured(
self, client, create_test_application, mock_mail, caplog
self, app, client, create_test_application, mock_mail, caplog
):
"""Test that HR notification is skipped when HR_EMAIL is not configured."""
# Ensure HR_EMAIL is not set
from app import app
app.config['HR_EMAIL'] = None
# Create a test application
@@ -97,9 +95,8 @@ class TestHRNotifications:
# Verify warning was logged
assert 'HR_EMAIL not configured' in caplog.text
def test_hr_notification_includes_file_count(self, client, create_test_application, mock_mail):
def test_hr_notification_includes_file_count(self, app, client, create_test_application, mock_mail):
"""Test that HR notification includes the count of uploaded files."""
from app import app
app.config['HR_EMAIL'] = 'hr@example.com'
app.config['APPLICATION_URL_BASE'] = 'http://localhost:5000'
@@ -146,9 +143,8 @@ class TestHRNotifications:
hr_email = mock_mail.sent_messages[0]
assert 'Anzahl der hochgeladenen Dokumente: 2' in hr_email.body
def test_hr_notification_with_zero_files(self, client, create_test_application, mock_mail):
def test_hr_notification_with_zero_files(self, app, client, create_test_application, mock_mail):
"""Test that HR notification works even when no files are uploaded."""
from app import app
app.config['HR_EMAIL'] = 'hr@example.com'
app.config['APPLICATION_URL_BASE'] = 'http://localhost:5000'
@@ -184,8 +180,6 @@ class TestHRNotifications:
def test_send_hr_notification_function_directly(self, app):
"""Test the send_hr_notification function directly."""
from app import send_hr_notification
app.config['HR_EMAIL'] = 'hr@example.com'
app.config['APPLICATION_URL_BASE'] = 'http://localhost:5000'
@@ -205,15 +199,13 @@ class TestHRNotifications:
with app.app_context():
# Mock mail.send to prevent actual sending
with patch('app.mail.send') as mock_send:
with patch('app.email_service.mail.send') as mock_send:
result = send_hr_notification(session_id, app_data)
assert result is True
assert mock_send.called
def test_send_hr_notification_handles_email_failure(self, app, caplog):
"""Test that send_hr_notification handles email sending failures gracefully."""
from app import send_hr_notification
app.config['HR_EMAIL'] = 'hr@example.com'
app.config['APPLICATION_URL_BASE'] = 'http://localhost:5000'
@@ -231,14 +223,13 @@ class TestHRNotifications:
with app.app_context():
# Mock mail.send to raise an exception
with patch('app.mail.send', side_effect=Exception('SMTP error')):
with patch('app.email_service.mail.send', side_effect=Exception('SMTP error')):
result = send_hr_notification(session_id, app_data)
assert result is False
assert 'Failed to send HR notification email' in caplog.text
def test_hr_notification_url_format(self, client, create_test_application, mock_mail):
def test_hr_notification_url_format(self, app, client, create_test_application, mock_mail):
"""Test that the application URL in HR notification is correctly formatted."""
from app import app
app.config['HR_EMAIL'] = 'hr@example.com'
app.config['APPLICATION_URL_BASE'] = 'https://example.com'