project initialization
Some checks failed
System Monitoring / Health Checks (push) Has been cancelled
System Monitoring / Performance Monitoring (push) Has been cancelled
System Monitoring / Database Monitoring (push) Has been cancelled
System Monitoring / Cache Monitoring (push) Has been cancelled
System Monitoring / Log Monitoring (push) Has been cancelled
System Monitoring / Resource Monitoring (push) Has been cancelled
System Monitoring / Uptime Monitoring (push) Has been cancelled
System Monitoring / Backup Monitoring (push) Has been cancelled
System Monitoring / Security Monitoring (push) Has been cancelled
System Monitoring / Monitoring Dashboard (push) Has been cancelled
System Monitoring / Alerting (push) Has been cancelled
Security Scanning / Dependency Scanning (push) Has been cancelled
Security Scanning / Code Security Scanning (push) Has been cancelled
Security Scanning / Secrets Scanning (push) Has been cancelled
Security Scanning / Container Security Scanning (push) Has been cancelled
Security Scanning / Compliance Checking (push) Has been cancelled
Security Scanning / Security Dashboard (push) Has been cancelled
Security Scanning / Security Remediation (push) Has been cancelled
Some checks failed
System Monitoring / Health Checks (push) Has been cancelled
System Monitoring / Performance Monitoring (push) Has been cancelled
System Monitoring / Database Monitoring (push) Has been cancelled
System Monitoring / Cache Monitoring (push) Has been cancelled
System Monitoring / Log Monitoring (push) Has been cancelled
System Monitoring / Resource Monitoring (push) Has been cancelled
System Monitoring / Uptime Monitoring (push) Has been cancelled
System Monitoring / Backup Monitoring (push) Has been cancelled
System Monitoring / Security Monitoring (push) Has been cancelled
System Monitoring / Monitoring Dashboard (push) Has been cancelled
System Monitoring / Alerting (push) Has been cancelled
Security Scanning / Dependency Scanning (push) Has been cancelled
Security Scanning / Code Security Scanning (push) Has been cancelled
Security Scanning / Secrets Scanning (push) Has been cancelled
Security Scanning / Container Security Scanning (push) Has been cancelled
Security Scanning / Compliance Checking (push) Has been cancelled
Security Scanning / Security Dashboard (push) Has been cancelled
Security Scanning / Security Remediation (push) Has been cancelled
This commit is contained in:
413
backend/tests/unit/models/test_education_models.py
Normal file
413
backend/tests/unit/models/test_education_models.py
Normal file
@@ -0,0 +1,413 @@
|
||||
"""
|
||||
Unit tests for Education Models
|
||||
|
||||
Tests for education module models:
|
||||
- Student
|
||||
- Class
|
||||
|
||||
Author: Claude
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from django.test import TestCase
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils import timezone
|
||||
from decimal import Decimal
|
||||
from datetime import date, time, timedelta
|
||||
|
||||
from backend.src.core.models.tenant import Tenant
|
||||
from backend.src.core.models.user import User
|
||||
from backend.src.modules.education.models.student import Student
|
||||
from backend.src.modules.education.models.class_model import Class
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class StudentModelTest(TestCase):
|
||||
"""Test cases for Student model"""
|
||||
|
||||
def setUp(self):
|
||||
self.tenant = Tenant.objects.create(
|
||||
name='Test Education Center',
|
||||
schema_name='test_education',
|
||||
domain='testeducation.com',
|
||||
business_type='education'
|
||||
)
|
||||
|
||||
self.user = User.objects.create_user(
|
||||
username='admin',
|
||||
email='admin@test.com',
|
||||
password='test123',
|
||||
tenant=self.tenant,
|
||||
role='admin'
|
||||
)
|
||||
|
||||
self.student_data = {
|
||||
'tenant': self.tenant,
|
||||
'student_id': 'S2024010001',
|
||||
'first_name': 'Ahmad',
|
||||
'last_name': 'Bin Ibrahim',
|
||||
'ic_number': '000101-01-0001',
|
||||
'gender': 'male',
|
||||
'date_of_birth': date(2010, 1, 1),
|
||||
'nationality': 'Malaysian',
|
||||
'religion': 'Islam',
|
||||
'race': 'Malay',
|
||||
'email': 'ahmad.student@test.com',
|
||||
'phone': '+60123456789',
|
||||
'address': '123 Student Street',
|
||||
'city': 'Kuala Lumpur',
|
||||
'state': 'KUL',
|
||||
'postal_code': '50000',
|
||||
'father_name': 'Ibrahim Bin Ali',
|
||||
'father_phone': '+60123456788',
|
||||
'father_occupation': 'Engineer',
|
||||
'mother_name': 'Aminah Binti Ahmad',
|
||||
'mother_phone': '+60123456787',
|
||||
'mother_occupation': 'Teacher',
|
||||
'emergency_contact_name': 'Ibrahim Bin Ali',
|
||||
'emergency_contact_phone': '+60123456788',
|
||||
'emergency_contact_relationship': 'Father',
|
||||
'previous_school': 'SK Test Primary',
|
||||
'previous_grade': '6A',
|
||||
'current_grade': 'Form 1',
|
||||
'stream': 'science',
|
||||
'admission_date': date.today(),
|
||||
'graduation_date': None,
|
||||
'status': 'active',
|
||||
'medical_conditions': 'None',
|
||||
'allergies': 'None',
|
||||
'special_needs': 'None',
|
||||
'is_active': True,
|
||||
'created_by': self.user
|
||||
}
|
||||
|
||||
def test_create_student(self):
|
||||
"""Test creating a new student"""
|
||||
student = Student.objects.create(**self.student_data)
|
||||
self.assertEqual(student.tenant, self.tenant)
|
||||
self.assertEqual(student.student_id, self.student_data['student_id'])
|
||||
self.assertEqual(student.first_name, self.student_data['first_name'])
|
||||
self.assertEqual(student.last_name, self.student_data['last_name'])
|
||||
self.assertEqual(student.ic_number, self.student_data['ic_number'])
|
||||
self.assertEqual(student.gender, self.student_data['gender'])
|
||||
self.assertEqual(student.current_grade, self.student_data['current_grade'])
|
||||
self.assertEqual(student.stream, self.student_data['stream'])
|
||||
self.assertEqual(student.status, self.student_data['status'])
|
||||
self.assertTrue(student.is_active)
|
||||
|
||||
def test_student_string_representation(self):
|
||||
"""Test student string representation"""
|
||||
student = Student.objects.create(**self.student_data)
|
||||
self.assertEqual(str(student), f"{student.first_name} {student.last_name} ({student.student_id})")
|
||||
|
||||
def test_student_full_name(self):
|
||||
"""Test student full name property"""
|
||||
student = Student.objects.create(**self.student_data)
|
||||
self.assertEqual(student.full_name, f"{student.first_name} {student.last_name}")
|
||||
|
||||
def test_student_age(self):
|
||||
"""Test student age calculation"""
|
||||
student = Student.objects.create(**self.student_data)
|
||||
|
||||
# Age should be calculated based on date of birth
|
||||
today = date.today()
|
||||
expected_age = today.year - student.date_of_birth.year
|
||||
if today.month < student.date_of_birth.month or (today.month == student.date_of_birth.month and today.day < student.date_of_birth.day):
|
||||
expected_age -= 1
|
||||
|
||||
self.assertEqual(student.age, expected_age)
|
||||
|
||||
def test_student_malaysian_ic_validation(self):
|
||||
"""Test Malaysian IC number validation"""
|
||||
# Valid IC number
|
||||
student = Student.objects.create(**self.student_data)
|
||||
self.assertEqual(student.ic_number, self.student_data['ic_number'])
|
||||
|
||||
# Invalid IC number format
|
||||
invalid_data = self.student_data.copy()
|
||||
invalid_data['ic_number'] = '123'
|
||||
with self.assertRaises(Exception):
|
||||
Student.objects.create(**invalid_data)
|
||||
|
||||
def test_student_gender_choices(self):
|
||||
"""Test student gender validation"""
|
||||
invalid_data = self.student_data.copy()
|
||||
invalid_data['gender'] = 'invalid_gender'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Student.objects.create(**invalid_data)
|
||||
|
||||
def test_student_grade_validation(self):
|
||||
"""Test student grade validation"""
|
||||
# Test valid grades
|
||||
valid_grades = ['Form 1', 'Form 2', 'Form 3', 'Form 4', 'Form 5', 'Form 6']
|
||||
for grade in valid_grades:
|
||||
data = self.student_data.copy()
|
||||
data['current_grade'] = grade
|
||||
student = Student.objects.create(**data)
|
||||
self.assertEqual(student.current_grade, grade)
|
||||
|
||||
# Test invalid grade
|
||||
invalid_data = self.student_data.copy()
|
||||
invalid_data['current_grade'] = 'Form 7'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Student.objects.create(**invalid_data)
|
||||
|
||||
def test_student_stream_choices(self):
|
||||
"""Test student stream validation"""
|
||||
# Test valid streams
|
||||
valid_streams = ['science', 'arts', 'commerce', 'technical']
|
||||
for stream in valid_streams:
|
||||
data = self.student_data.copy()
|
||||
data['stream'] = stream
|
||||
student = Student.objects.create(**data)
|
||||
self.assertEqual(student.stream, stream)
|
||||
|
||||
# Test invalid stream
|
||||
invalid_data = self.student_data.copy()
|
||||
invalid_data['stream'] = 'invalid_stream'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Student.objects.create(**invalid_data)
|
||||
|
||||
def test_student_status_choices(self):
|
||||
"""Test student status validation"""
|
||||
# Test valid statuses
|
||||
valid_statuses = ['active', 'inactive', 'graduated', 'transferred', 'suspended']
|
||||
for status in valid_statuses:
|
||||
data = self.student_data.copy()
|
||||
data['status'] = status
|
||||
student = Student.objects.create(**data)
|
||||
self.assertEqual(student.status, status)
|
||||
|
||||
# Test invalid status
|
||||
invalid_data = self.student_data.copy()
|
||||
invalid_data['status'] = 'invalid_status'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Student.objects.create(**invalid_data)
|
||||
|
||||
def test_student_parent_information(self):
|
||||
"""Test student parent information validation"""
|
||||
student = Student.objects.create(**self.student_data)
|
||||
|
||||
self.assertEqual(student.father_name, self.student_data['father_name'])
|
||||
self.assertEqual(student.mother_name, self.student_data['mother_name'])
|
||||
self.assertEqual(student.emergency_contact_name, self.student_data['emergency_contact_name'])
|
||||
|
||||
def test_student_malaysian_education_info(self):
|
||||
"""Test Malaysian education specific information"""
|
||||
student = Student.objects.create(**self.student_data)
|
||||
|
||||
self.assertEqual(student.religion, self.student_data['religion'])
|
||||
self.assertEqual(student.race, self.student_data['race'])
|
||||
self.assertEqual(student.previous_school, self.student_data['previous_school'])
|
||||
self.assertEqual(student.previous_grade, self.student_data['previous_grade'])
|
||||
|
||||
|
||||
class ClassModelTest(TestCase):
|
||||
"""Test cases for Class model"""
|
||||
|
||||
def setUp(self):
|
||||
self.tenant = Tenant.objects.create(
|
||||
name='Test Education Center',
|
||||
schema_name='test_education',
|
||||
domain='testeducation.com',
|
||||
business_type='education'
|
||||
)
|
||||
|
||||
self.teacher = User.objects.create_user(
|
||||
username='teacher',
|
||||
email='teacher@test.com',
|
||||
password='test123',
|
||||
tenant=self.tenant,
|
||||
role='staff'
|
||||
)
|
||||
|
||||
self.student = Student.objects.create(
|
||||
tenant=self.tenant,
|
||||
student_id='S2024010001',
|
||||
first_name='Ahmad',
|
||||
last_name='Bin Ibrahim',
|
||||
ic_number='000101-01-0001',
|
||||
gender='male',
|
||||
date_of_birth=date(2010, 1, 1),
|
||||
current_grade='Form 1',
|
||||
stream='science',
|
||||
admission_date=date.today(),
|
||||
status='active'
|
||||
)
|
||||
|
||||
self.class_data = {
|
||||
'tenant': self.tenant,
|
||||
'class_name': 'Mathematics Form 1',
|
||||
'class_code': 'MATH-F1-2024',
|
||||
'grade': 'Form 1',
|
||||
'stream': 'science',
|
||||
'subject': 'Mathematics',
|
||||
'academic_year': '2024',
|
||||
'semester': '1',
|
||||
'teacher': self.teacher,
|
||||
'room': 'B1-01',
|
||||
'max_students': 30,
|
||||
'schedule_days': ['Monday', 'Wednesday', 'Friday'],
|
||||
'start_time': time(8, 0),
|
||||
'end_time': time(9, 30),
|
||||
'start_date': date.today(),
|
||||
'end_date': date.today() + timedelta(days=180),
|
||||
'is_active': True,
|
||||
'syllabus': 'KSSM Mathematics Form 1',
|
||||
'objectives': 'Complete KSSM Mathematics syllabus',
|
||||
'assessment_methods': 'Tests, Assignments, Projects',
|
||||
'created_by': self.teacher
|
||||
}
|
||||
|
||||
def test_create_class(self):
|
||||
"""Test creating a new class"""
|
||||
class_obj = Class.objects.create(**self.class_data)
|
||||
self.assertEqual(class_obj.tenant, self.tenant)
|
||||
self.assertEqual(class_obj.class_name, self.class_data['class_name'])
|
||||
self.assertEqual(class_obj.class_code, self.class_data['class_code'])
|
||||
self.assertEqual(class_obj.grade, self.class_data['grade'])
|
||||
self.assertEqual(class_obj.stream, self.class_data['stream'])
|
||||
self.assertEqual(class_obj.subject, self.class_data['subject'])
|
||||
self.assertEqual(class_obj.teacher, self.teacher)
|
||||
self.assertEqual(class_obj.max_students, self.class_data['max_students'])
|
||||
self.assertTrue(class_obj.is_active)
|
||||
|
||||
def test_class_string_representation(self):
|
||||
"""Test class string representation"""
|
||||
class_obj = Class.objects.create(**self.class_data)
|
||||
self.assertEqual(str(class_obj), f"{class_obj.class_name} ({class_obj.class_code})")
|
||||
|
||||
def test_class_duration(self):
|
||||
"""Test class duration calculation"""
|
||||
class_obj = Class.objects.create(**self.class_data)
|
||||
|
||||
# Duration should be 90 minutes
|
||||
self.assertEqual(class_obj.duration, 90)
|
||||
|
||||
def test_class_grade_validation(self):
|
||||
"""Test class grade validation"""
|
||||
# Test valid grades
|
||||
valid_grades = ['Form 1', 'Form 2', 'Form 3', 'Form 4', 'Form 5', 'Form 6']
|
||||
for grade in valid_grades:
|
||||
data = self.class_data.copy()
|
||||
data['grade'] = grade
|
||||
class_obj = Class.objects.create(**data)
|
||||
self.assertEqual(class_obj.grade, grade)
|
||||
|
||||
# Test invalid grade
|
||||
invalid_data = self.class_data.copy()
|
||||
invalid_data['grade'] = 'Form 7'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Class.objects.create(**invalid_data)
|
||||
|
||||
def test_class_stream_choices(self):
|
||||
"""Test class stream validation"""
|
||||
# Test valid streams
|
||||
valid_streams = ['science', 'arts', 'commerce', 'technical']
|
||||
for stream in valid_streams:
|
||||
data = self.class_data.copy()
|
||||
data['stream'] = stream
|
||||
class_obj = Class.objects.create(**data)
|
||||
self.assertEqual(class_obj.stream, stream)
|
||||
|
||||
# Test invalid stream
|
||||
invalid_data = self.class_data.copy()
|
||||
invalid_data['stream'] = 'invalid_stream'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Class.objects.create(**invalid_data)
|
||||
|
||||
def test_class_semester_choices(self):
|
||||
"""Test class semester validation"""
|
||||
# Test valid semesters
|
||||
valid_semesters = ['1', '2']
|
||||
for semester in valid_semesters:
|
||||
data = self.class_data.copy()
|
||||
data['semester'] = semester
|
||||
class_obj = Class.objects.create(**data)
|
||||
self.assertEqual(class_obj.semester, semester)
|
||||
|
||||
# Test invalid semester
|
||||
invalid_data = self.class_data.copy()
|
||||
invalid_data['semester'] = '3'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Class.objects.create(**invalid_data)
|
||||
|
||||
def test_class_schedule_validation(self):
|
||||
"""Test class schedule validation"""
|
||||
# Valid schedule
|
||||
class_obj = Class.objects.create(**self.class_data)
|
||||
self.assertEqual(class_obj.schedule_days, self.class_data['schedule_days'])
|
||||
self.assertEqual(class_obj.start_time, self.class_data['start_time'])
|
||||
self.assertEqual(class_obj.end_time, self.class_data['end_time'])
|
||||
|
||||
# Invalid time range (end before start)
|
||||
invalid_data = self.class_data.copy()
|
||||
invalid_data['start_time'] = time(10, 0)
|
||||
invalid_data['end_time'] = time(9, 30)
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Class.objects.create(**invalid_data)
|
||||
|
||||
def test_class_student_enrollment(self):
|
||||
"""Test class student enrollment"""
|
||||
class_obj = Class.objects.create(**self.class_data)
|
||||
|
||||
# Add student to class
|
||||
class_obj.students.add(self.student)
|
||||
|
||||
self.assertIn(self.student, class_obj.students.all())
|
||||
self.assertEqual(class_obj.students.count(), 1)
|
||||
|
||||
def test_class_capacity_validation(self):
|
||||
"""Test class capacity validation"""
|
||||
class_obj = Class.objects.create(**self.class_data)
|
||||
|
||||
# Test capacity
|
||||
self.assertEqual(class_obj.max_students, 30)
|
||||
|
||||
# Test is_full method
|
||||
self.assertFalse(class_obj.is_full)
|
||||
|
||||
# Add students up to capacity
|
||||
for i in range(30):
|
||||
student_data = self.student.__dict__.copy()
|
||||
student_data['student_id'] = f'S202401{i:04d}'
|
||||
student_data['first_name'] = f'Student{i}'
|
||||
student_data.pop('id', None)
|
||||
student_data.pop('_state', None)
|
||||
|
||||
student = Student.objects.create(**student_data)
|
||||
class_obj.students.add(student)
|
||||
|
||||
# Should be full now
|
||||
self.assertTrue(class_obj.is_full)
|
||||
|
||||
def test_class_malaysian_education_features(self):
|
||||
"""Test Malaysian education specific features"""
|
||||
class_obj = Class.objects.create(**self.class_data)
|
||||
|
||||
self.assertEqual(class_obj.subject, self.class_data['subject'])
|
||||
self.assertEqual(class_obj.academic_year, self.class_data['academic_year'])
|
||||
self.assertEqual(class_obj.syllabus, self.class_data['syllabus'])
|
||||
|
||||
def test_class_date_validation(self):
|
||||
"""Test class date validation"""
|
||||
# Valid date range
|
||||
class_obj = Class.objects.create(**self.class_data)
|
||||
self.assertLessEqual(class_obj.start_date, class_obj.end_date)
|
||||
|
||||
# Invalid date range (end before start)
|
||||
invalid_data = self.class_data.copy()
|
||||
invalid_data['start_date'] = date.today()
|
||||
invalid_data['end_date'] = date.today() - timedelta(days=1)
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Class.objects.create(**invalid_data)
|
||||
Reference in New Issue
Block a user