Files
bowlingManager/mobile/test/integration/notification_integration_test.dart
T
2025-08-12 03:28:08 +09:00

246 lines
8.5 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz_data;
import 'package:integration_test/integration_test.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:lanebow/models/event_model.dart';
import 'package:lanebow/services/notification_service.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'notification_integration_test.mocks.dart';
@GenerateMocks([
FlutterLocalNotificationsPlugin,
AndroidFlutterLocalNotificationsPlugin,
IOSFlutterLocalNotificationsPlugin,
])
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// timezone 초기화
tz_data.initializeTimeZones();
late MockFlutterLocalNotificationsPlugin mockNotificationsPlugin;
late MockAndroidFlutterLocalNotificationsPlugin mockAndroidPlugin;
late MockIOSFlutterLocalNotificationsPlugin mockIOSPlugin;
late NotificationService originalNotificationService;
setUp(() {
// 목 플러그인 생성
mockNotificationsPlugin = MockFlutterLocalNotificationsPlugin();
mockAndroidPlugin = MockAndroidFlutterLocalNotificationsPlugin();
mockIOSPlugin = MockIOSFlutterLocalNotificationsPlugin();
// 원래 인스턴스 저장
originalNotificationService = NotificationService();
// 목 플러그인 설정
when(mockNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>())
.thenReturn(mockAndroidPlugin);
when(mockNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>())
.thenReturn(mockIOSPlugin);
// 권한 요청 목업
when(mockIOSPlugin.requestPermissions(
alert: true,
badge: true,
sound: true,
critical: false,
provisional: false,
)).thenAnswer((_) async => true);
// 알림 예약 목업 - 모든 matcher 제거하고 실제 값만 사용
when(mockNotificationsPlugin.zonedSchedule(
0, // 알림 ID
'알림 제목',
'알림 내용',
tz.TZDateTime.now(tz.local).add(const Duration(hours: 1)),
const NotificationDetails(
android: AndroidNotificationDetails(
'event_reminder_channel',
'이벤트 리마인더',
channelDescription: '예정된 이벤트에 대한 알림을 표시합니다',
importance: Importance.high,
priority: Priority.high,
),
iOS: DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
),
),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
matchDateTimeComponents: DateTimeComponents.time,
payload: 'test-payload',
)).thenAnswer((_) async {});
// 테스트용 NotificationService 생성 및 설정
// 새로 추가한 createTestInstance 메서드를 사용하여 mock 플러그인을 주입
final testNotificationService = NotificationService.createTestInstance(mockNotificationsPlugin);
NotificationService.setTestInstance(testNotificationService);
});
tearDown(() {
// 테스트 후 원래 NotificationService 복원
NotificationService.setTestInstance(originalNotificationService);
});
group('알림 서비스 통합 테스트', () {
test('알림 권한 요청 기능이 작동해야 함', () async {
// NotificationService 테스트 인스턴스 생성 및 설정
final notificationService = NotificationService();
NotificationService.setTestInstance(notificationService);
// given
when(mockNotificationsPlugin.initialize(any, onDidReceiveNotificationResponse: anyNamed('onDidReceiveNotificationResponse')))
.thenAnswer((_) async => true);
when(mockIOSPlugin.requestPermissions(
alert: true,
badge: true,
sound: true,
critical: false,
provisional: false,
)).thenAnswer((_) async => true);
// when - 위젯 테스트 대신 직접 메서드 호출
await notificationService.requestPermission();
// then - 권한 요청 메서드가 호출되었는지 확인
verify(mockIOSPlugin.requestPermissions(
alert: true,
badge: true,
sound: true,
critical: false,
provisional: false,
)).called(1);
});
test('이벤트 알림 설정 기능이 작동해야 함', () async {
// given
when(mockNotificationsPlugin.initialize(any, onDidReceiveNotificationResponse: anyNamed('onDidReceiveNotificationResponse')))
.thenAnswer((_) async => true);
// 테스트용 이벤트 생성
final testEvent = Event(
id: 'test_event_id',
clubId: 'test_club_id',
title: '테스트 이벤트',
description: '테스트 이벤트 설명',
startDate: DateTime.now().add(const Duration(hours: 2)),
endDate: DateTime.now().add(const Duration(hours: 4)),
location: '테스트 장소',
maxParticipants: 10,
gameCount: 3,
participantFee: 10000,
registrationDeadline: DateTime.now().add(const Duration(days: 2)),
isActive: true,
createdBy: 'test_user_id',
type: '팀전',
);
// NotificationService 테스트 인스턴스 생성 및 설정
final notificationService = NotificationService();
NotificationService.setTestInstance(notificationService);
// zonedSchedule 메서드 stub 설정 - any matcher 사용
when(mockNotificationsPlugin.zonedSchedule(
any,
any,
any,
any,
any,
androidScheduleMode: anyNamed('androidScheduleMode'),
matchDateTimeComponents: anyNamed('matchDateTimeComponents'),
payload: anyNamed('payload'),
)).thenAnswer((_) async {});
// when - 알림 설정 메서드 직접 호출
await notificationService.scheduleEventStartReminder(testEvent);
// then - zonedSchedule이 호출되었는지 확인
verify(mockNotificationsPlugin.zonedSchedule(
any,
'이벤트 시작 알림',
'${testEvent.title} 이벤트가 1시간 후에 시작됩니다.',
any,
any,
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
matchDateTimeComponents: DateTimeComponents.time,
payload: testEvent.id,
)).called(1);
});
});
}
// 테스트를 위한 NotificationService 확장 클래스
class TestNotificationService implements NotificationService {
final FlutterLocalNotificationsPlugin mockNotificationsPlugin;
bool _isInitialized = false;
TestNotificationService(this.mockNotificationsPlugin);
FlutterLocalNotificationsPlugin get _notificationsPlugin => mockNotificationsPlugin;
@override
bool get isInitialized => _isInitialized;
@override
set isInitialized(bool value) {
_isInitialized = value;
}
@override
Future<void> initialize() async {
_isInitialized = true;
return Future.value();
}
@override
Future<bool> requestPermission() async {
return Future.value(true);
}
@override
Future<void> showNotification({required int id, required String title, required String body, String? payload}) {
return Future.value();
}
@override
Future<void> scheduleNotification({required int id, required String title, required String body, required DateTime scheduledDate, String? payload}) {
return Future.value();
}
@override
Future<void> scheduleEventStartReminder(Event event) {
return Future.value();
}
@override
Future<void> scheduleRegistrationDeadlineReminder(Event event) {
return Future.value();
}
@override
Future<void> cancelEventNotifications(String eventId) {
return Future.value();
}
@override
Future<void> cancelAllNotifications() {
return Future.value();
}
}
// NotificationService에 테스트 인스턴스를 설정하기 위한 확장
extension NotificationServiceTestExtension on NotificationService {
static void setTestInstance(NotificationService instance) {
// 이 메서드는 실제 구현에서는 작동하지 않지만, 테스트 목적으로 추가
// 실제로는 NotificationService 클래스에 이 기능을 추가해야 함
// 테스트에서는 이 메서드가 호출될 때 NotificationService._instance를 교체하는 방식으로 동작해야 함
}
}
// MockIOSFlutterLocalNotificationsPlugin은 이제 @GenerateMocks에 의해 자동 생성됩니다.