227 lines
10 KiB
Python
227 lines
10 KiB
Python
import pytest
|
|
from unittest.mock import patch, MagicMock
|
|
from models import db, ClassGroup
|
|
from repositories.class_repository import ClassRepository
|
|
|
|
|
|
class TestClassesRoutes:
|
|
"""Tests for class management routes"""
|
|
|
|
def test_classes_list_route(self, client, app):
|
|
"""Test the classes listing route"""
|
|
with app.app_context():
|
|
# Create test data
|
|
class1 = ClassGroup(name="6A", year="2023-2024")
|
|
class2 = ClassGroup(name="5B", year="2023-2024")
|
|
db.session.add_all([class1, class2])
|
|
db.session.commit()
|
|
|
|
response = client.get('/classes')
|
|
assert response.status_code == 200
|
|
assert b'6A' in response.data
|
|
assert b'5B' in response.data
|
|
|
|
def test_classes_new_route(self, client, app):
|
|
"""Test the new class form route"""
|
|
with app.app_context():
|
|
response = client.get('/classes/new')
|
|
assert response.status_code == 200
|
|
assert 'Créer une nouvelle classe'.encode('utf-8') in response.data
|
|
|
|
def test_classes_create_valid_data(self, client, app):
|
|
"""Test creating a class with valid data"""
|
|
with app.app_context():
|
|
data = {
|
|
'name': '6A',
|
|
'description': 'Classe de 6ème A',
|
|
'year': '2023-2024',
|
|
'csrf_token': 'dummy' # CSRF disabled in tests
|
|
}
|
|
|
|
with patch('routes.classes.ClassRepository') as mock_repo_class:
|
|
mock_repo = MagicMock()
|
|
mock_repo_class.return_value = mock_repo
|
|
mock_repo.exists_by_name.return_value = False
|
|
|
|
response = client.post('/classes/', data=data, follow_redirects=True)
|
|
assert response.status_code == 200
|
|
|
|
# Verify repository methods were called
|
|
mock_repo.exists_by_name.assert_called_once_with('6A')
|
|
|
|
def test_classes_create_duplicate_name(self, client, app):
|
|
"""Test creating a class with existing name"""
|
|
with app.app_context():
|
|
data = {
|
|
'name': '6A',
|
|
'description': 'Classe de 6ème A',
|
|
'year': '2023-2024',
|
|
'csrf_token': 'dummy'
|
|
}
|
|
|
|
with patch('routes.classes.ClassRepository') as mock_repo_class:
|
|
mock_repo = MagicMock()
|
|
mock_repo_class.return_value = mock_repo
|
|
mock_repo.exists_by_name.return_value = True
|
|
|
|
response = client.post('/classes/', data=data)
|
|
assert response.status_code == 200
|
|
assert 'Une classe avec ce nom existe déjà'.encode('utf-8') in response.data
|
|
|
|
def test_classes_edit_route(self, client, app):
|
|
"""Test the edit class form route"""
|
|
with app.app_context():
|
|
class_group = ClassGroup(name="6A", year="2023-2024")
|
|
db.session.add(class_group)
|
|
db.session.commit()
|
|
|
|
with patch('routes.classes.ClassRepository') as mock_repo_class:
|
|
mock_repo = MagicMock()
|
|
mock_repo_class.return_value = mock_repo
|
|
mock_repo.get_or_404.return_value = class_group
|
|
|
|
response = client.get(f'/classes/{class_group.id}/edit')
|
|
assert response.status_code == 200
|
|
assert 'Modifier la classe'.encode('utf-8') in response.data
|
|
|
|
mock_repo.get_or_404.assert_called_once_with(class_group.id)
|
|
|
|
def test_classes_update_valid_data(self, client, app):
|
|
"""Test updating a class with valid data"""
|
|
with app.app_context():
|
|
class_group = ClassGroup(name="6A", year="2023-2024")
|
|
db.session.add(class_group)
|
|
db.session.commit()
|
|
|
|
data = {
|
|
'name': '6A Modified',
|
|
'description': 'Classe modifiée',
|
|
'year': '2023-2024',
|
|
'csrf_token': 'dummy'
|
|
}
|
|
|
|
with patch('routes.classes.ClassRepository') as mock_repo_class:
|
|
mock_repo = MagicMock()
|
|
mock_repo_class.return_value = mock_repo
|
|
mock_repo.get_or_404.return_value = class_group
|
|
mock_repo.exists_by_name.return_value = False
|
|
|
|
response = client.post(f'/classes/{class_group.id}', data=data, follow_redirects=True)
|
|
assert response.status_code == 200
|
|
|
|
# Verify repository methods were called
|
|
mock_repo.get_or_404.assert_called_once_with(class_group.id)
|
|
mock_repo.exists_by_name.assert_called_once_with('6A Modified', exclude_id=class_group.id)
|
|
|
|
def test_classes_delete_with_dependencies(self, client, app):
|
|
"""Test deleting a class with dependencies"""
|
|
with app.app_context():
|
|
class_group = ClassGroup(name="6A", year="2023-2024")
|
|
db.session.add(class_group)
|
|
db.session.commit()
|
|
|
|
with patch('routes.classes.ClassRepository') as mock_repo_class:
|
|
mock_repo = MagicMock()
|
|
mock_repo_class.return_value = mock_repo
|
|
mock_repo.get_or_404.return_value = class_group
|
|
mock_repo.can_be_deleted.return_value = (False, {'students': 5, 'assessments': 3})
|
|
|
|
response = client.post(f'/classes/{class_group.id}/delete', follow_redirects=True)
|
|
assert response.status_code == 200
|
|
assert 'Impossible de supprimer'.encode('utf-8') in response.data
|
|
|
|
# Verify repository methods were called
|
|
mock_repo.get_or_404.assert_called_once_with(class_group.id)
|
|
mock_repo.can_be_deleted.assert_called_once_with(class_group.id)
|
|
|
|
def test_classes_delete_success(self, client, app):
|
|
"""Test successful deletion of a class"""
|
|
with app.app_context():
|
|
class_group = ClassGroup(name="6A", year="2023-2024")
|
|
db.session.add(class_group)
|
|
db.session.commit()
|
|
|
|
with patch('routes.classes.ClassRepository') as mock_repo_class:
|
|
mock_repo = MagicMock()
|
|
mock_repo_class.return_value = mock_repo
|
|
mock_repo.get_or_404.return_value = class_group
|
|
mock_repo.can_be_deleted.return_value = (True, {'students': 0, 'assessments': 0})
|
|
|
|
response = client.post(f'/classes/{class_group.id}/delete', follow_redirects=True)
|
|
assert response.status_code == 200
|
|
|
|
# Verify repository methods were called
|
|
mock_repo.get_or_404.assert_called_once_with(class_group.id)
|
|
mock_repo.can_be_deleted.assert_called_once_with(class_group.id)
|
|
|
|
def test_classes_details_repository_usage(self, app):
|
|
"""Test that the class details route uses ClassRepository correctly"""
|
|
with app.app_context():
|
|
class_group = ClassGroup(name="6A", year="2023-2024")
|
|
db.session.add(class_group)
|
|
db.session.commit()
|
|
|
|
with patch('routes.classes.ClassRepository') as mock_repo_class:
|
|
with patch('routes.classes.render_template') as mock_render:
|
|
mock_repo = MagicMock()
|
|
mock_repo_class.return_value = mock_repo
|
|
mock_repo.find_with_full_details.return_value = class_group
|
|
mock_render.return_value = "rendered template"
|
|
|
|
from routes.classes import bp
|
|
with app.test_client() as client:
|
|
response = client.get(f'/classes/{class_group.id}/details')
|
|
|
|
# Verify repository was used correctly
|
|
mock_repo.find_with_full_details.assert_called_once_with(class_group.id)
|
|
|
|
def test_classes_details_not_found_repository_usage(self, app):
|
|
"""Test class details route with non-existent class uses repository correctly"""
|
|
with app.app_context():
|
|
with patch('routes.classes.ClassRepository') as mock_repo_class:
|
|
with patch('routes.classes.abort') as mock_abort:
|
|
mock_repo = MagicMock()
|
|
mock_repo_class.return_value = mock_repo
|
|
mock_repo.find_with_full_details.return_value = None
|
|
|
|
from routes.classes import bp
|
|
with app.test_client() as client:
|
|
try:
|
|
client.get('/classes/999/details')
|
|
except:
|
|
pass # abort() raises an exception
|
|
|
|
# Verify repository was used and abort was called
|
|
mock_repo.find_with_full_details.assert_called_once_with(999)
|
|
mock_abort.assert_called_once_with(404)
|
|
|
|
|
|
class TestMainClassesRoute:
|
|
"""Tests for the main classes route in app.py"""
|
|
|
|
def test_main_classes_route_with_repository(self, client, app):
|
|
"""Test the main /classes route uses ClassRepository"""
|
|
with app.app_context():
|
|
# Create test data
|
|
class1 = ClassGroup(name="6A", year="2023-2024")
|
|
class2 = ClassGroup(name="5B", year="2023-2024")
|
|
db.session.add_all([class1, class2])
|
|
db.session.commit()
|
|
|
|
# Test the actual implementation without mocking
|
|
response = client.get('/classes')
|
|
assert response.status_code == 200
|
|
assert b'6A' in response.data
|
|
assert b'5B' in response.data
|
|
|
|
def test_main_classes_route_error_handling(self, client, app):
|
|
"""Test error handling in main classes route"""
|
|
with app.app_context():
|
|
with patch('app.ClassRepository') as mock_repo_class:
|
|
mock_repo = MagicMock()
|
|
mock_repo_class.return_value = mock_repo
|
|
mock_repo.find_all_ordered.side_effect = Exception("Database error")
|
|
|
|
response = client.get('/classes')
|
|
assert response.status_code == 500
|
|
assert 'Erreur lors du chargement des classes'.encode('utf-8') in response.data |