tdd 진행
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:lanebow/main.dart' as app;
|
||||
import 'package:lanebow/services/notification_service.dart';
|
||||
import 'package:lanebow/models/event_model.dart';
|
||||
import 'package:lanebow/screens/club/event_details_screen.dart';
|
||||
|
||||
@GenerateMocks([FlutterLocalNotificationsPlugin])
|
||||
import 'notification_integration_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
late MockFlutterLocalNotificationsPlugin mockNotificationsPlugin;
|
||||
late NotificationService originalNotificationService;
|
||||
|
||||
setUp(() {
|
||||
mockNotificationsPlugin = MockFlutterLocalNotificationsPlugin();
|
||||
|
||||
// 원래 NotificationService 인스턴스 저장
|
||||
originalNotificationService = NotificationService();
|
||||
|
||||
// 모킹된 NotificationService 설정
|
||||
TestNotificationService testService = TestNotificationService(mockNotificationsPlugin);
|
||||
NotificationService.setTestInstance(testService);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
// 테스트 후 원래 NotificationService 복원
|
||||
NotificationService.setTestInstance(originalNotificationService);
|
||||
});
|
||||
|
||||
group('알림 서비스 통합 테스트', () {
|
||||
testWidgets('홈 화면에서 알림 권한 요청 버튼이 작동해야 함', (WidgetTester tester) async {
|
||||
// given
|
||||
when(mockNotificationsPlugin.initialize(any, onDidReceiveNotificationResponse: anyNamed('onDidReceiveNotificationResponse')))
|
||||
.thenAnswer((_) async => true);
|
||||
|
||||
final mockIOSPlugin = MockIOSFlutterLocalNotificationsPlugin();
|
||||
when(mockNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>())
|
||||
.thenReturn(mockIOSPlugin);
|
||||
when(mockIOSPlugin.requestPermissions(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
critical: false,
|
||||
provisional: false,
|
||||
)).thenAnswer((_) async => true);
|
||||
|
||||
// when
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.notifications),
|
||||
onPressed: () async {
|
||||
await NotificationService().requestPermission();
|
||||
ScaffoldMessenger.of(tester.element(find.byType(Scaffold)))
|
||||
.showSnackBar(SnackBar(content: Text('알림 권한 요청됨')));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 홈 화면의 앱바에서 알림 아이콘 찾기
|
||||
final notificationIconFinder = find.byIcon(Icons.notifications);
|
||||
expect(notificationIconFinder, findsOneWidget);
|
||||
|
||||
// 알림 아이콘 탭
|
||||
await tester.tap(notificationIconFinder);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// then
|
||||
// 권한 요청 메서드가 호출되었는지 확인
|
||||
verify(mockIOSPlugin.requestPermissions(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
critical: false,
|
||||
provisional: false,
|
||||
)).called(1);
|
||||
|
||||
// 스낵바가 표시되었는지 확인
|
||||
expect(find.byType(SnackBar), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('이벤트 상세 화면에서 알림 설정 버튼이 작동해야 함', (WidgetTester tester) async {
|
||||
// given
|
||||
when(mockNotificationsPlugin.initialize(any, onDidReceiveNotificationResponse: anyNamed('onDidReceiveNotificationResponse')))
|
||||
.thenAnswer((_) async => true);
|
||||
|
||||
final mockIOSPlugin = MockIOSFlutterLocalNotificationsPlugin();
|
||||
when(mockNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>())
|
||||
.thenReturn(mockIOSPlugin);
|
||||
when(mockIOSPlugin.requestPermissions(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
critical: false,
|
||||
provisional: false,
|
||||
)).thenAnswer((_) async => true);
|
||||
|
||||
when(mockNotificationsPlugin.zonedSchedule(
|
||||
any, any, any, any, any,
|
||||
androidScheduleMode: anyNamed('androidScheduleMode'),
|
||||
matchDateTimeComponents: anyNamed('matchDateTimeComponents'),
|
||||
payload: anyNamed('payload'),
|
||||
)).thenAnswer((_) async {});
|
||||
|
||||
// 테스트용 이벤트 생성
|
||||
final testEvent = Event(
|
||||
id: 'test_event_id',
|
||||
clubId: 'test_club_id',
|
||||
title: '테스트 이벤트',
|
||||
startDate: DateTime.now().add(const Duration(hours: 2)),
|
||||
registrationDeadline: DateTime.now().add(const Duration(days: 2)),
|
||||
isActive: true,
|
||||
);
|
||||
|
||||
// when
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: EventDetailsScreen(event: testEvent),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 기본 정보 탭으로 이동 (기본적으로 선택되어 있을 수 있음)
|
||||
final basicInfoTabFinder = find.text('기본 정보');
|
||||
if (basicInfoTabFinder.evaluate().isNotEmpty) {
|
||||
await tester.tap(basicInfoTabFinder);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
// 알림 설정 버튼 찾기
|
||||
final notificationButtonFinder = find.text('알림 설정');
|
||||
expect(notificationButtonFinder, findsOneWidget);
|
||||
|
||||
// 알림 설정 버튼 탭
|
||||
await tester.tap(notificationButtonFinder);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 다이얼로그가 표시되었는지 확인
|
||||
expect(find.text('알림 설정'), findsWidgets); // 다이얼로그 제목도 '알림 설정'이므로 여러 개 찾아짐
|
||||
expect(find.text('이벤트 시작 알림 (1시간 전)'), findsOneWidget);
|
||||
expect(find.text('등록 마감 알림 (1일 전)'), findsOneWidget);
|
||||
|
||||
// 이벤트 시작 알림 옵션 선택
|
||||
final startReminderFinder = find.text('이벤트 시작 알림 (1시간 전)');
|
||||
await tester.tap(startReminderFinder);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// then
|
||||
// 알림 예약 메서드가 호출되었는지 확인
|
||||
verify(mockNotificationsPlugin.zonedSchedule(
|
||||
testEvent.id.hashCode, '이벤트 시작 알림', '${testEvent.title} 이벤트가 1시간 후에 시작됩니다.', any, any,
|
||||
androidScheduleMode: anyNamed('androidScheduleMode'),
|
||||
matchDateTimeComponents: anyNamed('matchDateTimeComponents'),
|
||||
payload: testEvent.id,
|
||||
)).called(1);
|
||||
|
||||
// 스낵바가 표시되었는지 확인
|
||||
expect(find.byType(SnackBar), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 테스트를 위한 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 클래스에 이 기능을 추가해야 함
|
||||
}
|
||||
}
|
||||
|
||||
// 모킹된 iOS 플러그인
|
||||
class MockIOSFlutterLocalNotificationsPlugin extends Mock
|
||||
implements IOSFlutterLocalNotificationsPlugin {
|
||||
@override
|
||||
Future<bool?> requestPermissions({
|
||||
bool alert = false,
|
||||
bool badge = false,
|
||||
bool sound = false,
|
||||
bool critical = false,
|
||||
bool provisional = false, // 추가 파라미터
|
||||
}) async {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user