refact: use repositories patterns for classes
This commit is contained in:
		
							
								
								
									
										227
									
								
								tests/test_routes_classes.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								tests/test_routes_classes.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | ||||
| 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('flask.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 | ||||
		Reference in New Issue
	
	Block a user