Files
bowlingManager/mobile/test/services/subscription_service_test.dart

216 lines
7.0 KiB
Dart

import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:mockito/annotations.dart';
import 'package:http/http.dart' as http;
import 'package:lanebow/services/subscription_service.dart';
import 'package:lanebow/services/in_app_purchase_service.dart';
import 'package:lanebow/utils/test_utils.dart';
import '../utils/event_bus_test_utils.dart';
// 모킹 클래스 생성
@GenerateMocks([http.Client, InAppPurchaseService])
import 'subscription_service_test.mocks.dart';
void main() {
late SubscriptionService subscriptionService;
late MockClient mockClient;
late MockInAppPurchaseService mockPurchaseService;
final testToken = 'test_token';
final testClubId = 'test_club_id';
final testUserId = 'test_user_id';
// 테스트 구독 데이터
final testSubscription = {
'id': 'test_subscription_id',
'userId': testUserId,
'clubId': testClubId,
'planType': 'premium',
'status': 'active',
'startDate': DateTime.now().toIso8601String(),
'endDate': DateTime.now().add(Duration(days: 30)).toIso8601String(),
'price': 19900.0,
'currency': 'KRW',
'autoRenew': true,
'features': {
'maxMembers': 100,
'maxEvents': 100,
},
'paymentMethod': 'card',
'transactionId': 'test_transaction_id',
'createdAt': DateTime.now().subtract(Duration(days: 10)).toIso8601String(),
'updatedAt': DateTime.now().toIso8601String(),
};
// 테스트 구독 플랜 데이터
final testPlans = [
{
'type': 'basic',
'name': '기본',
'description': '중소규모 클럽을 위한 확장 기능',
'monthlyPrice': 9900.0,
'yearlyPrice': 99000.0,
'currency': 'KRW',
'features': [
'최대 30명 회원 관리',
'상세 점수 분석',
'이벤트 관리',
'회원 통계',
],
'maxMembers': 30,
'maxEvents': 20,
'hasAdvancedStats': true,
'hasCustomization': false,
'hasPriority': false,
},
{
'type': 'premium',
'name': '프리미엄',
'description': '대규모 클럽을 위한 고급 기능',
'monthlyPrice': 19900.0,
'yearlyPrice': 199000.0,
'currency': 'KRW',
'features': [
'무제한 회원 관리',
'고급 통계 및 분석',
'무제한 이벤트',
'맞춤형 보고서',
'우선 지원',
],
'maxMembers': 100,
'maxEvents': 100,
'hasAdvancedStats': true,
'hasCustomization': true,
'hasPriority': true,
}
];
setUp(() async {
// 테스트 모드 강제 설정
TestUtils.setTestMode(true);
// 테스트별 고유 ID 생성 및 설정
final testId = 'subscription_service_test_${DateTime.now().millisecondsSinceEpoch}';
await EventBusTestUtils.setUp(testId);
// HTTP 클라이언트 모킹
mockClient = MockClient();
// InAppPurchaseService 모킹
mockPurchaseService = MockInAppPurchaseService();
// HTTP 클라이언트 요청 모킹
when(mockClient.post(
any,
headers: anyNamed('headers'),
body: anyNamed('body'),
)).thenAnswer((_) async => http.Response(jsonEncode(testSubscription), 200));
when(mockClient.get(
any,
headers: anyNamed('headers'),
)).thenAnswer((_) async => http.Response(jsonEncode(testPlans), 200));
// 모킹 서비스에 대한 기본 동작 정의
when(mockPurchaseService.isLoading).thenReturn(false);
when(mockPurchaseService.error).thenReturn(null);
when(mockPurchaseService.products).thenReturn([]);
when(mockPurchaseService.restorePurchases()).thenAnswer((_) async => true);
// SubscriptionService 초기화 - 테스트용 생성자 사용
subscriptionService = SubscriptionService.forTest(
client: mockClient,
purchaseService: mockPurchaseService,
userId: testUserId,
token: testToken,
clubId: testClubId,
);
});
tearDown(() async {
// 테스트에서 생성된 SubscriptionService 정리
try { subscriptionService.dispose(); } catch (_) {}
// EventBus 표준 정리
await EventBusTestUtils.tearDown();
// 테스트 모드 해제
TestUtils.setTestMode(false);
});
group('SubscriptionService 기본 기능 테스트', () {
test('SubscriptionService 초기화 테스트', () {
// 초기화 후 기본 상태 확인
expect(subscriptionService, isNotNull);
expect(subscriptionService.currentSubscription, isNull);
expect(subscriptionService.isLoading, isNotNull);
expect(subscriptionService.availablePlans, isNotNull);
});
test('loadCurrentSubscription 메서드가 현재 구독 정보를 가져와야 함', () async {
// given
when(mockClient.post(
any,
headers: anyNamed('headers'),
body: anyNamed('body'),
)).thenAnswer((_) async => http.Response(jsonEncode(testSubscription), 200));
// when
await subscriptionService.loadCurrentSubscription();
// then
expect(subscriptionService.currentSubscription, isNotNull);
expect(subscriptionService.isLoading, isFalse);
expect(subscriptionService.error, isNull);
});
test('canUseFeature 메서드가 기능 사용 가능 여부를 확인해야 함', () {
// 구독이 없는 경우 기능 사용 가능 여부 확인
expect(subscriptionService.canUseFeature('advancedStats'), isA<bool>());
});
test('getMaxMembers 메서드가 최대 회원 수를 반환해야 함', () {
// 구독이 없는 경우 기본 무료 플랜의 최대 회원 수 반환
final maxMembers = subscriptionService.getMaxMembers();
expect(maxMembers, isNotNull);
expect(maxMembers, isA<int>());
});
test('getMaxEvents 메서드가 최대 이벤트 수를 반환해야 함', () {
// 구독이 없는 경우 기본 무료 플랜의 최대 이벤트 수 반환
final maxEvents = subscriptionService.getMaxEvents();
expect(maxEvents, isNotNull);
expect(maxEvents, isA<int>());
});
test('purchaseService getter가 null이 아니어야 함', () {
expect(subscriptionService.purchaseService, isNotNull);
});
test('hasSubscription getter가 동작해야 함', () {
expect(subscriptionService.hasSubscription, isA<bool>());
});
test('isActive getter가 동작해야 함', () {
expect(subscriptionService.isActive, isA<bool>());
});
test('restoreSubscriptions 메서드가 구독을 복원해야 함', () async {
// given
when(mockPurchaseService.restorePurchases()).thenAnswer((_) async => true);
when(mockClient.post(
any,
headers: anyNamed('headers'),
body: anyNamed('body'),
)).thenAnswer((_) async => http.Response(jsonEncode(testSubscription), 200));
// when
final result = await subscriptionService.restoreSubscriptions();
// then
expect(result, isTrue);
expect(subscriptionService.isLoading, isFalse);
});
});
}