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:
323
backend/tests/unit/models/test_healthcare_models.py
Normal file
323
backend/tests/unit/models/test_healthcare_models.py
Normal file
@@ -0,0 +1,323 @@
|
||||
"""
|
||||
Unit tests for Healthcare Models
|
||||
|
||||
Tests for healthcare module models:
|
||||
- Patient
|
||||
- Appointment
|
||||
|
||||
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.healthcare.models.patient import Patient
|
||||
from backend.src.modules.healthcare.models.appointment import Appointment
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class PatientModelTest(TestCase):
|
||||
"""Test cases for Patient model"""
|
||||
|
||||
def setUp(self):
|
||||
self.tenant = Tenant.objects.create(
|
||||
name='Test Healthcare Sdn Bhd',
|
||||
schema_name='test_healthcare',
|
||||
domain='testhealthcare.com',
|
||||
business_type='healthcare'
|
||||
)
|
||||
|
||||
self.user = User.objects.create_user(
|
||||
username='doctor',
|
||||
email='doctor@test.com',
|
||||
password='test123',
|
||||
tenant=self.tenant,
|
||||
role='staff'
|
||||
)
|
||||
|
||||
self.patient_data = {
|
||||
'tenant': self.tenant,
|
||||
'patient_id': 'P2024010001',
|
||||
'first_name': 'John',
|
||||
'last_name': 'Doe',
|
||||
'ic_number': '000101-01-0001',
|
||||
'passport_number': '',
|
||||
'nationality': 'Malaysian',
|
||||
'gender': 'male',
|
||||
'date_of_birth': date(1990, 1, 1),
|
||||
'blood_type': 'O+',
|
||||
'email': 'john.doe@test.com',
|
||||
'phone': '+60123456789',
|
||||
'emergency_contact_name': 'Jane Doe',
|
||||
'emergency_contact_phone': '+60123456788',
|
||||
'emergency_contact_relationship': 'Spouse',
|
||||
'address': '123 Test Street',
|
||||
'city': 'Kuala Lumpur',
|
||||
'state': 'KUL',
|
||||
'postal_code': '50000',
|
||||
'medical_history': 'No significant medical history',
|
||||
'allergies': 'None known',
|
||||
'current_medications': 'None',
|
||||
'chronic_conditions': 'None',
|
||||
'last_visit_date': None,
|
||||
'is_active': True,
|
||||
'created_by': self.user
|
||||
}
|
||||
|
||||
def test_create_patient(self):
|
||||
"""Test creating a new patient"""
|
||||
patient = Patient.objects.create(**self.patient_data)
|
||||
self.assertEqual(patient.tenant, self.tenant)
|
||||
self.assertEqual(patient.patient_id, self.patient_data['patient_id'])
|
||||
self.assertEqual(patient.first_name, self.patient_data['first_name'])
|
||||
self.assertEqual(patient.last_name, self.patient_data['last_name'])
|
||||
self.assertEqual(patient.ic_number, self.patient_data['ic_number'])
|
||||
self.assertEqual(patient.gender, self.patient_data['gender'])
|
||||
self.assertEqual(patient.blood_type, self.patient_data['blood_type'])
|
||||
self.assertTrue(patient.is_active)
|
||||
|
||||
def test_patient_string_representation(self):
|
||||
"""Test patient string representation"""
|
||||
patient = Patient.objects.create(**self.patient_data)
|
||||
self.assertEqual(str(patient), f"{patient.first_name} {patient.last_name} ({patient.patient_id})")
|
||||
|
||||
def test_patient_full_name(self):
|
||||
"""Test patient full name property"""
|
||||
patient = Patient.objects.create(**self.patient_data)
|
||||
self.assertEqual(patient.full_name, f"{patient.first_name} {patient.last_name}")
|
||||
|
||||
def test_patient_age(self):
|
||||
"""Test patient age calculation"""
|
||||
patient = Patient.objects.create(**self.patient_data)
|
||||
|
||||
# Age should be calculated based on date of birth
|
||||
today = date.today()
|
||||
expected_age = today.year - patient.date_of_birth.year
|
||||
if today.month < patient.date_of_birth.month or (today.month == patient.date_of_birth.month and today.day < patient.date_of_birth.day):
|
||||
expected_age -= 1
|
||||
|
||||
self.assertEqual(patient.age, expected_age)
|
||||
|
||||
def test_patient_malaysian_ic_validation(self):
|
||||
"""Test Malaysian IC number validation"""
|
||||
# Valid IC number
|
||||
patient = Patient.objects.create(**self.patient_data)
|
||||
self.assertEqual(patient.ic_number, self.patient_data['ic_number'])
|
||||
|
||||
# Invalid IC number format
|
||||
invalid_data = self.patient_data.copy()
|
||||
invalid_data['ic_number'] = '123'
|
||||
with self.assertRaises(Exception):
|
||||
Patient.objects.create(**invalid_data)
|
||||
|
||||
def test_patient_gender_choices(self):
|
||||
"""Test patient gender validation"""
|
||||
invalid_data = self.patient_data.copy()
|
||||
invalid_data['gender'] = 'invalid_gender'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Patient.objects.create(**invalid_data)
|
||||
|
||||
def test_patient_blood_type_choices(self):
|
||||
"""Test patient blood type validation"""
|
||||
invalid_data = self.patient_data.copy()
|
||||
invalid_data['blood_type'] = 'Z+'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Patient.objects.create(**invalid_data)
|
||||
|
||||
def test_patient_phone_validation(self):
|
||||
"""Test Malaysian phone number validation"""
|
||||
# Valid Malaysian phone number
|
||||
patient = Patient.objects.create(**self.patient_data)
|
||||
self.assertEqual(patient.phone, self.patient_data['phone'])
|
||||
|
||||
# Invalid phone number
|
||||
invalid_data = self.patient_data.copy()
|
||||
invalid_data['phone'] = '12345'
|
||||
with self.assertRaises(Exception):
|
||||
Patient.objects.create(**invalid_data)
|
||||
|
||||
def test_patient_medical_info_validation(self):
|
||||
"""Test patient medical information validation"""
|
||||
# Test with medical conditions
|
||||
data = self.patient_data.copy()
|
||||
data['chronic_conditions'] = 'Diabetes, Hypertension'
|
||||
data['allergies'] = 'Penicillin, Sulfa drugs'
|
||||
|
||||
patient = Patient.objects.create(**data)
|
||||
self.assertEqual(patient.chronic_conditions, 'Diabetes, Hypertension')
|
||||
self.assertEqual(patient.allergies, 'Penicillin, Sulfa drugs')
|
||||
|
||||
|
||||
class AppointmentModelTest(TestCase):
|
||||
"""Test cases for Appointment model"""
|
||||
|
||||
def setUp(self):
|
||||
self.tenant = Tenant.objects.create(
|
||||
name='Test Healthcare Sdn Bhd',
|
||||
schema_name='test_healthcare',
|
||||
domain='testhealthcare.com',
|
||||
business_type='healthcare'
|
||||
)
|
||||
|
||||
self.doctor = User.objects.create_user(
|
||||
username='doctor',
|
||||
email='doctor@test.com',
|
||||
password='test123',
|
||||
tenant=self.tenant,
|
||||
role='staff'
|
||||
)
|
||||
|
||||
self.patient = Patient.objects.create(
|
||||
tenant=self.tenant,
|
||||
patient_id='P2024010001',
|
||||
first_name='John',
|
||||
last_name='Doe',
|
||||
ic_number='000101-01-0001',
|
||||
gender='male',
|
||||
date_of_birth=date(1990, 1, 1),
|
||||
blood_type='O+',
|
||||
phone='+60123456789',
|
||||
created_by=self.doctor
|
||||
)
|
||||
|
||||
self.appointment_data = {
|
||||
'tenant': self.tenant,
|
||||
'patient': self.patient,
|
||||
'doctor': self.doctor,
|
||||
'appointment_number': 'APT-2024010001',
|
||||
'appointment_date': date.today() + timedelta(days=1),
|
||||
'appointment_time': time(10, 0),
|
||||
'end_time': time(10, 30),
|
||||
'appointment_type': 'consultation',
|
||||
'status': 'scheduled',
|
||||
'reason': 'General checkup',
|
||||
'notes': '',
|
||||
'is_telemedicine': False,
|
||||
'telemedicine_link': '',
|
||||
'reminder_sent': False,
|
||||
'created_by': self.doctor
|
||||
}
|
||||
|
||||
def test_create_appointment(self):
|
||||
"""Test creating a new appointment"""
|
||||
appointment = Appointment.objects.create(**self.appointment_data)
|
||||
self.assertEqual(appointment.tenant, self.tenant)
|
||||
self.assertEqual(appointment.patient, self.patient)
|
||||
self.assertEqual(appointment.doctor, self.doctor)
|
||||
self.assertEqual(appointment.appointment_number, self.appointment_data['appointment_number'])
|
||||
self.assertEqual(appointment.status, self.appointment_data['status'])
|
||||
self.assertEqual(appointment.appointment_type, self.appointment_data['appointment_type'])
|
||||
self.assertFalse(appointment.is_telemedicine)
|
||||
|
||||
def test_appointment_string_representation(self):
|
||||
"""Test appointment string representation"""
|
||||
appointment = Appointment.objects.create(**self.appointment_data)
|
||||
expected = f"{self.patient.full_name} - {appointment.appointment_date} at {appointment.appointment_time}"
|
||||
self.assertEqual(str(appointment), expected)
|
||||
|
||||
def test_appointment_duration(self):
|
||||
"""Test appointment duration calculation"""
|
||||
appointment = Appointment.objects.create(**self.appointment_data)
|
||||
|
||||
# Duration should be 30 minutes
|
||||
self.assertEqual(appointment.duration, 30)
|
||||
|
||||
def test_appointment_is_upcoming(self):
|
||||
"""Test appointment upcoming status"""
|
||||
# Future appointment
|
||||
appointment = Appointment.objects.create(**self.appointment_data)
|
||||
self.assertTrue(appointment.is_upcoming)
|
||||
|
||||
# Past appointment
|
||||
appointment.appointment_date = date.today() - timedelta(days=1)
|
||||
appointment.save()
|
||||
self.assertFalse(appointment.is_upcoming)
|
||||
|
||||
def test_appointment_status_choices(self):
|
||||
"""Test appointment status validation"""
|
||||
invalid_data = self.appointment_data.copy()
|
||||
invalid_data['status'] = 'invalid_status'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Appointment.objects.create(**invalid_data)
|
||||
|
||||
def test_appointment_type_choices(self):
|
||||
"""Test appointment type validation"""
|
||||
invalid_data = self.appointment_data.copy()
|
||||
invalid_data['appointment_type'] = 'invalid_type'
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Appointment.objects.create(**invalid_data)
|
||||
|
||||
def test_appointment_time_validation(self):
|
||||
"""Test appointment time validation"""
|
||||
# Valid time range
|
||||
appointment = Appointment.objects.create(**self.appointment_data)
|
||||
self.assertEqual(appointment.appointment_time, self.appointment_data['appointment_time'])
|
||||
self.assertEqual(appointment.end_time, self.appointment_data['end_time'])
|
||||
|
||||
# Invalid time range (end before start)
|
||||
invalid_data = self.appointment_data.copy()
|
||||
invalid_data['appointment_time'] = time(11, 0)
|
||||
invalid_data['end_time'] = time(10, 30)
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Appointment.objects.create(**invalid_data)
|
||||
|
||||
def test_appointment_conflict_detection(self):
|
||||
"""Test appointment conflict detection"""
|
||||
# Create first appointment
|
||||
appointment1 = Appointment.objects.create(**self.appointment_data)
|
||||
|
||||
# Try to create conflicting appointment
|
||||
conflict_data = self.appointment_data.copy()
|
||||
conflict_data['appointment_number'] = 'APT-2024010002'
|
||||
conflict_data['appointment_time'] = time(10, 15)
|
||||
conflict_data['end_time'] = time(10, 45)
|
||||
|
||||
# This should not raise an exception but conflict detection should be available
|
||||
appointment2 = Appointment.objects.create(**conflict_data)
|
||||
|
||||
# Check if there's a conflict
|
||||
self.assertTrue(
|
||||
appointment1.appointment_date == appointment2.appointment_date and
|
||||
appointment1.doctor == appointment2.doctor and
|
||||
(
|
||||
(appointment1.appointment_time <= appointment2.appointment_time < appointment1.end_time) or
|
||||
(appointment2.appointment_time <= appointment1.appointment_time < appointment2.end_time)
|
||||
)
|
||||
)
|
||||
|
||||
def test_telemedicine_appointment(self):
|
||||
"""Test telemedicine appointment features"""
|
||||
data = self.appointment_data.copy()
|
||||
data['is_telemedicine'] = True
|
||||
data['telemedicine_link'] = 'https://meet.test.com/room/12345'
|
||||
|
||||
appointment = Appointment.objects.create(**data)
|
||||
self.assertTrue(appointment.is_telemedicine)
|
||||
self.assertEqual(appointment.telemedicine_link, data['telemedicine_link'])
|
||||
|
||||
def test_appointment_reminder_features(self):
|
||||
"""Test appointment reminder features"""
|
||||
appointment = Appointment.objects.create(**self.appointment_data)
|
||||
|
||||
# Initially no reminder sent
|
||||
self.assertFalse(appointment.reminder_sent)
|
||||
|
||||
# Mark reminder as sent
|
||||
appointment.reminder_sent = True
|
||||
appointment.reminder_sent_at = timezone.now()
|
||||
appointment.save()
|
||||
|
||||
self.assertTrue(appointment.reminder_sent)
|
||||
self.assertIsNotNone(appointment.reminder_sent_at)
|
||||
Reference in New Issue
Block a user