""" 평가 엔진 테스트 모듈 종합 평가 엔진의 기능을 검증합니다. """ import unittest import numpy as np import sys import os import tempfile import shutil from pathlib import Path # 프로젝트 루트를 Python 경로에 추가 project_root = Path(__file__).parent.parent sys.path.insert(0, str(project_root)) from src.evaluator import Evaluator from config.evaluation_config import EVALUATION_CONFIG class TestEvaluator(unittest.TestCase): """평가 엔진 테스트""" def setUp(self): """테스트 설정""" # 임시 디렉토리 생성 self.temp_dir = tempfile.mkdtemp() # 테스트용 더미 파일 생성 self.create_dummy_files() # 평가 엔진 초기화 self.evaluator = Evaluator() def tearDown(self): """테스트 정리""" # 임시 디렉토리 삭제 shutil.rmtree(self.temp_dir) def create_dummy_files(self): """테스트용 더미 파일 생성""" # 더미 GLB 파일 생성 (실제로는 간단한 텍스트 파일) self.model_path = os.path.join(self.temp_dir, "test_model.glb") with open(self.model_path, 'w') as f: f.write("dummy glb content") # 더미 이미지 파일 생성 (실제로는 간단한 텍스트 파일) self.reference_path = os.path.join(self.temp_dir, "test_image.png") with open(self.reference_path, 'w') as f: f.write("dummy image content") def test_evaluator_initialization(self): """평가 엔진 초기화 테스트""" self.assertIsNotNone(self.evaluator) self.assertIsNotNone(self.evaluator.data_loader) self.assertIsNotNone(self.evaluator.renderer) self.assertIsNotNone(self.evaluator.map_2d_calculator) self.assertIsNotNone(self.evaluator.map_3d_calculator) self.assertIsNotNone(self.evaluator.chamfer_calculator) self.assertIsNotNone(self.evaluator.emd_calculator) self.assertIsNotNone(self.evaluator.class_accuracy_calculator) def test_calculate_comprehensive_score(self): """종합 점수 계산 테스트""" # 테스트용 메트릭 데이터 metrics = { '2d_map': 0.8, '3d_map': 0.7, 'chamfer_distance': 0.01, 'emd': 0.02, 'class_accuracy': 0.85 } score, details = self.evaluator.calculate_comprehensive_score(metrics) # 종합 점수는 0과 100 사이의 값이어야 함 self.assertGreaterEqual(score, 0.0) self.assertLessEqual(score, 100.0) # 세부사항은 딕셔너리여야 함 self.assertIsInstance(details, dict) self.assertEqual(len(details), len(metrics)) def test_determine_grade(self): """성능 등급 결정 테스트""" # A등급 테스트 grade_a = self.evaluator.determine_grade(95.0) self.assertEqual(grade_a, 'A') # B등급 테스트 grade_b = self.evaluator.determine_grade(85.0) self.assertEqual(grade_b, 'B') # C등급 테스트 grade_c = self.evaluator.determine_grade(75.0) self.assertEqual(grade_c, 'C') # D등급 테스트 grade_d = self.evaluator.determine_grade(65.0) self.assertEqual(grade_d, 'D') # F등급 테스트 grade_f = self.evaluator.determine_grade(50.0) self.assertEqual(grade_f, 'F') def test_validate_input_files(self): """입력 파일 검증 테스트""" # 유효한 파일들 valid = self.evaluator._validate_input_files(self.model_path, self.reference_path) self.assertTrue(valid) # 존재하지 않는 파일 invalid = self.evaluator._validate_input_files("nonexistent.glb", "nonexistent.png") self.assertFalse(invalid) def test_create_3d_ground_truth(self): """3D Ground Truth 생성 테스트""" # 테스트용 3D 모델 model_3d = { 'vertices': np.random.rand(100, 3), 'faces': np.random.randint(0, 100, (50, 3)), 'center': np.array([0, 0, 0]), 'scale': np.array([1, 1, 1]), 'bounding_box': (np.array([-1, -1, -1]), np.array([1, 1, 1])) } reference_image = np.random.randint(0, 255, (512, 512, 3), dtype=np.uint8) ground_truth = self.evaluator._create_3d_ground_truth(model_3d, reference_image) # Ground Truth는 딕셔너리여야 함 self.assertIsInstance(ground_truth, dict) self.assertIn('vertices', ground_truth) self.assertIn('faces', ground_truth) self.assertIn('classes', ground_truth) self.assertIn('bounding_boxes', ground_truth) def test_generate_report(self): """리포트 생성 테스트""" # 테스트용 결과 데이터 results = { 'comprehensive_score': 85.5, 'grade': 'B', 'evaluation_timestamp': '2024-01-01T00:00:00', 'model_path': self.model_path, 'reference_path': self.reference_path, 'metrics': { '2d_map': 0.8, '3d_map': 0.7, 'chamfer_distance': 0.01, 'emd': 0.02, 'class_accuracy': 0.85 }, 'score_details': { '2d_map': { 'raw_value': 0.8, 'normalized_score': 80.0, 'weight': 0.25, 'weighted_score': 20.0, 'threshold': 0.8 } } } # HTML 리포트 생성 html_report = self.evaluator.generate_report(results) self.assertIsInstance(html_report, str) self.assertIn('', html_report) self.assertIn('3D 객체인식 평가 결과', html_report) # JSON 리포트 생성 self.evaluator.config['output']['report_format'] = 'json' json_report = self.evaluator.generate_report(results) self.assertIsInstance(json_report, str) # 텍스트 리포트 생성 self.evaluator.config['output']['report_format'] = 'txt' text_report = self.evaluator.generate_report(results) self.assertIsInstance(text_report, str) self.assertIn('TRELLIS 모델 평가 결과', text_report) class TestConfiguration(unittest.TestCase): """설정 테스트""" def test_evaluation_config_structure(self): """평가 설정 구조 테스트""" config = EVALUATION_CONFIG # 필수 키들이 존재하는지 확인 required_keys = [ 'weights', 'thresholds', 'rendering', 'pointcloud', 'classification', 'grade_thresholds', 'iou_thresholds', 'output', 'file_paths', 'logging', 'performance', 'validation' ] for key in required_keys: self.assertIn(key, config) def test_weights_sum(self): """가중치 합이 1.0인지 테스트""" weights = EVALUATION_CONFIG['weights'] weight_sum = sum(weights.values()) # 가중치 합은 1.0에 가까워야 함 self.assertAlmostEqual(weight_sum, 1.0, places=6) def test_thresholds_range(self): """임계값이 유효한 범위인지 테스트""" thresholds = EVALUATION_CONFIG['thresholds'] for metric, threshold in thresholds.items(): # 임계값은 0과 1 사이의 값이어야 함 self.assertGreaterEqual(threshold, 0.0) self.assertLessEqual(threshold, 1.0) def test_grade_thresholds_order(self): """등급 임계값이 올바른 순서인지 테스트""" grade_thresholds = EVALUATION_CONFIG['grade_thresholds'] # 등급 임계값은 내림차순이어야 함 values = list(grade_thresholds.values()) self.assertEqual(values, sorted(values, reverse=True)) if __name__ == '__main__': # 테스트 실행 unittest.main(verbosity=2)