import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:superport/data/models/maintenance_stats_dto.dart'; import 'package:superport/data/repositories/maintenance_stats_repository.dart'; import 'package:superport/domain/usecases/get_maintenance_stats_usecase.dart'; import 'package:superport/screens/maintenance/controllers/maintenance_dashboard_controller.dart'; // Mock 클래스 생성 class MockMaintenanceStatsRepository extends Mock implements MaintenanceStatsRepository {} void main() { group('Maintenance Dashboard Integration Tests', () { late MockMaintenanceStatsRepository mockRepository; late GetMaintenanceStatsUseCase useCase; late MaintenanceDashboardController controller; setUp(() { mockRepository = MockMaintenanceStatsRepository(); useCase = GetMaintenanceStatsUseCase(repository: mockRepository); controller = MaintenanceDashboardController( getMaintenanceStatsUseCase: useCase, ); }); test('should initialize with empty stats', () { // Assert expect(controller.stats, equals(const MaintenanceStatsDto())); expect(controller.isLoading, false); expect(controller.errorMessage, null); }); test('should load dashboard stats successfully', () async { // Arrange const mockStats = MaintenanceStatsDto( activeContracts: 10, totalContracts: 15, expiring60Days: 5, expiring30Days: 3, expiring7Days: 1, expiredContracts: 2, warrantyContracts: 8, maintenanceContracts: 5, inspectionContracts: 2, upcomingInspections: 3, overdueMaintenances: 1, totalRevenueAtRisk: 500000.0, completionRate: 0.85, updatedAt: null, ); when(mockRepository.getMaintenanceStats()) .thenAnswer((_) async => mockStats); // Act await controller.loadDashboardStats(); // Assert expect(controller.stats, equals(mockStats)); expect(controller.isLoading, false); expect(controller.errorMessage, null); expect(controller.hasValidData, false); // updatedAt가 null이므로 // 카드 데이터 검증 final cards = controller.dashboardCards; expect(cards.length, 4); expect(cards[0].count, 5); // 60일 내 expect(cards[1].count, 3); // 30일 내 expect(cards[2].count, 1); // 7일 내 expect(cards[3].count, 2); // 만료됨 }); test('should handle error state properly', () async { // Arrange when(mockRepository.getMaintenanceStats()) .thenThrow(Exception('Network error')); // Act await controller.loadDashboardStats(); // Assert expect(controller.isLoading, false); expect(controller.errorMessage, contains('Network error')); expect(controller.stats, equals(const MaintenanceStatsDto())); }); test('should calculate risk score correctly', () async { // Arrange const highRiskStats = MaintenanceStatsDto( totalContracts: 10, expiring7Days: 3, // 30% 가중치 expiring30Days: 2, // 20% 가중치 expiring60Days: 1, // 10% 가중치 expiredContracts: 4, // 40% 가중치 ); when(mockRepository.getMaintenanceStats()) .thenAnswer((_) async => highRiskStats); // Act await controller.loadDashboardStats(); // Assert final riskScore = controller.riskScore; expect(riskScore, greaterThan(0.8)); // 높은 위험도 expect(controller.riskStatus, MaintenanceCardStatus.critical); }); test('should format revenue at risk correctly', () async { // Arrange const statsWithRevenue = MaintenanceStatsDto( totalRevenueAtRisk: 1500000.0, // 150만원 ); when(mockRepository.getMaintenanceStats()) .thenAnswer((_) async => statsWithRevenue); // Act await controller.loadDashboardStats(); // Assert expect(controller.formattedRevenueAtRisk, '1.5백만원'); }); test('should handle refresh correctly', () async { // Arrange const mockStats = MaintenanceStatsDto( activeContracts: 5, updatedAt: null, ); when(mockRepository.getMaintenanceStats()) .thenAnswer((_) async => mockStats); // Act await controller.refreshDashboardStats(); // Assert expect(controller.isRefreshing, false); expect(controller.stats.activeContracts, 5); expect(controller.lastUpdated, isNotNull); }); test('should detect when refresh is needed', () { // Assert - 초기 상태에서는 새로고침 필요 expect(controller.needsRefresh, true); // 업데이트 시뮬레이션 controller.loadDashboardStats(); // 즉시는 새로고침 불필요 (실제로는 시간이 지나야 true) // 이 테스트는 로직의 존재 여부만 확인 expect(controller.timeSinceLastUpdate, isNotEmpty); }); test('should provide card status correctly', () { // 각 카드 상태 테스트 expect(controller.expiring60DaysCard.title, '60일 내'); expect(controller.expiring30DaysCard.title, '30일 내'); expect(controller.expiring7DaysCard.title, '7일 내'); expect(controller.expiredContractsCard.title, '만료됨'); // 기본 상태에서는 모두 active 상태여야 함 expect(controller.expiring60DaysCard.status, MaintenanceCardStatus.active); expect(controller.expiring30DaysCard.status, MaintenanceCardStatus.active); expect(controller.expiring7DaysCard.status, MaintenanceCardStatus.active); expect(controller.expiredContractsCard.status, MaintenanceCardStatus.active); }); }); group('MaintenanceStatsDto Tests', () { test('should create dashboard cards correctly', () { // Arrange const stats = MaintenanceStatsDto( expiring60Days: 10, expiring30Days: 5, expiring7Days: 2, expiredContracts: 3, ); // Act final cards = stats.dashboardCards; // Assert expect(cards.length, 4); expect(cards[0].count, 10); expect(cards[0].status, MaintenanceCardStatus.warning); expect(cards[1].count, 5); expect(cards[1].status, MaintenanceCardStatus.urgent); expect(cards[2].count, 2); expect(cards[2].status, MaintenanceCardStatus.critical); expect(cards[3].count, 3); expect(cards[3].status, MaintenanceCardStatus.expired); }); test('should calculate risk score correctly', () { // Arrange const lowRiskStats = MaintenanceStatsDto( totalContracts: 100, expiring60Days: 5, // 5% expiring30Days: 2, // 2% expiring7Days: 0, // 0% expiredContracts: 1, // 1% ); const highRiskStats = MaintenanceStatsDto( totalContracts: 10, expiring60Days: 2, // 20% expiring30Days: 3, // 30% expiring7Days: 2, // 20% expiredContracts: 3, // 30% ); // Act & Assert expect(lowRiskStats.riskScore, lessThan(0.3)); expect(lowRiskStats.riskStatus, MaintenanceCardStatus.active); expect(highRiskStats.riskScore, greaterThan(0.7)); expect(highRiskStats.riskStatus, MaintenanceCardStatus.critical); }); }); }