Files
notytex/tests/test_routes_classes.py

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