- 모든 서비스 메서드 시그니처를 실제 구현에 맞게 수정 - TestDataGenerator 제거하고 직접 객체 생성으로 변경 - 모델 필드명 및 타입 불일치 수정 - 불필요한 Either 패턴 사용 제거 - null safety 관련 이슈 해결 수정된 파일: - test/integration/screens/company_integration_test.dart - test/integration/screens/equipment_integration_test.dart - test/integration/screens/user_integration_test.dart - test/integration/screens/login_integration_test.dart
269 lines
9.9 KiB
Dart
269 lines
9.9 KiB
Dart
import 'package:dio/dio.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
import 'package:get_it/get_it.dart';
|
|
import 'package:superport/data/datasources/remote/api_client.dart';
|
|
import 'package:superport/data/datasources/remote/auth_remote_datasource.dart';
|
|
import 'package:superport/data/datasources/remote/company_remote_datasource.dart';
|
|
import 'package:superport/data/datasources/remote/user_remote_datasource.dart';
|
|
import 'package:superport/data/datasources/remote/equipment_remote_datasource.dart';
|
|
import 'package:superport/data/datasources/remote/license_remote_datasource.dart';
|
|
import 'package:superport/data/datasources/remote/warehouse_remote_datasource.dart';
|
|
import 'package:superport/data/datasources/remote/dashboard_remote_datasource.dart';
|
|
import 'package:superport/data/models/auth/login_request.dart';
|
|
import 'package:superport/services/auth_service.dart';
|
|
import 'package:superport/services/company_service.dart';
|
|
import 'package:superport/services/user_service.dart';
|
|
import 'package:superport/services/equipment_service.dart';
|
|
import 'package:superport/services/license_service.dart';
|
|
import 'package:superport/services/warehouse_service.dart';
|
|
import 'package:superport/services/dashboard_service.dart';
|
|
import 'package:superport/core/config/environment.dart';
|
|
|
|
/// 테스트용 메모리 기반 FlutterSecureStorage
|
|
class TestSecureStorage extends FlutterSecureStorage {
|
|
static final Map<String, String> _storage = {};
|
|
|
|
const TestSecureStorage() : super();
|
|
|
|
@override
|
|
Future<bool> containsKey({required String key, IOSOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, WebOptions? webOptions, MacOsOptions? mOptions, WindowsOptions? wOptions}) async {
|
|
return _storage.containsKey(key);
|
|
}
|
|
|
|
@override
|
|
Future<void> delete({required String key, IOSOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, WebOptions? webOptions, MacOsOptions? mOptions, WindowsOptions? wOptions}) async {
|
|
_storage.remove(key);
|
|
}
|
|
|
|
@override
|
|
Future<void> deleteAll({IOSOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, WebOptions? webOptions, MacOsOptions? mOptions, WindowsOptions? wOptions}) async {
|
|
_storage.clear();
|
|
}
|
|
|
|
@override
|
|
Future<String?> read({required String key, IOSOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, WebOptions? webOptions, MacOsOptions? mOptions, WindowsOptions? wOptions}) async {
|
|
return _storage[key];
|
|
}
|
|
|
|
@override
|
|
Future<Map<String, String>> readAll({IOSOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, WebOptions? webOptions, MacOsOptions? mOptions, WindowsOptions? wOptions}) async {
|
|
return Map.from(_storage);
|
|
}
|
|
|
|
@override
|
|
Future<void> write({required String key, required String? value, IOSOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, WebOptions? webOptions, MacOsOptions? mOptions, WindowsOptions? wOptions}) async {
|
|
if (value != null) {
|
|
_storage[key] = value;
|
|
} else {
|
|
_storage.remove(key);
|
|
}
|
|
}
|
|
|
|
// 테스트용 메서드
|
|
static void clearAll() {
|
|
_storage.clear();
|
|
}
|
|
}
|
|
|
|
/// 실제 API 테스트를 위한 헬퍼 클래스
|
|
class RealApiTestHelper {
|
|
static late GetIt getIt;
|
|
static late ApiClient apiClient;
|
|
static late FlutterSecureStorage secureStorage;
|
|
static late AuthService authService;
|
|
static String? _accessToken;
|
|
|
|
/// 테스트 환경 초기화
|
|
static Future<void> setupTestEnvironment() async {
|
|
// Environment 초기화
|
|
await Environment.initialize('development');
|
|
|
|
// 테스트 환경에서는 TestWidgetsFlutterBinding을 사용하지 않음
|
|
// HTTP 요청이 차단되기 때문
|
|
|
|
getIt = GetIt.instance;
|
|
|
|
// GetIt 초기화
|
|
if (getIt.isRegistered<ApiClient>()) {
|
|
await getIt.reset();
|
|
}
|
|
|
|
// 실제 API 클라이언트 설정
|
|
apiClient = ApiClient();
|
|
secureStorage = const TestSecureStorage();
|
|
|
|
// 서비스 등록
|
|
getIt.registerSingleton<ApiClient>(apiClient);
|
|
getIt.registerSingleton<FlutterSecureStorage>(secureStorage);
|
|
|
|
// Auth 서비스 등록
|
|
final authRemoteDataSource = AuthRemoteDataSourceImpl(apiClient);
|
|
authService = AuthServiceImpl(authRemoteDataSource, secureStorage);
|
|
getIt.registerSingleton<AuthService>(authService);
|
|
|
|
// RemoteDataSource 등록 (일부 서비스가 GetIt을 통해 가져옴)
|
|
final companyRemoteDataSource = CompanyRemoteDataSourceImpl(apiClient);
|
|
final licenseRemoteDataSource = LicenseRemoteDataSourceImpl(apiClient: apiClient);
|
|
final warehouseRemoteDataSource = WarehouseRemoteDataSourceImpl(apiClient: apiClient);
|
|
final equipmentRemoteDataSource = EquipmentRemoteDataSourceImpl();
|
|
final userRemoteDataSource = UserRemoteDataSource();
|
|
final dashboardRemoteDataSource = DashboardRemoteDataSourceImpl(apiClient);
|
|
|
|
getIt.registerSingleton<CompanyRemoteDataSource>(companyRemoteDataSource);
|
|
getIt.registerSingleton<LicenseRemoteDataSource>(licenseRemoteDataSource);
|
|
getIt.registerSingleton<WarehouseRemoteDataSource>(warehouseRemoteDataSource);
|
|
getIt.registerSingleton<EquipmentRemoteDataSource>(equipmentRemoteDataSource);
|
|
getIt.registerSingleton<UserRemoteDataSource>(userRemoteDataSource);
|
|
getIt.registerSingleton<DashboardRemoteDataSource>(dashboardRemoteDataSource);
|
|
|
|
// 기타 서비스 등록
|
|
getIt.registerSingleton<CompanyService>(CompanyService(companyRemoteDataSource));
|
|
getIt.registerSingleton<UserService>(UserService());
|
|
getIt.registerSingleton<EquipmentService>(EquipmentService());
|
|
getIt.registerSingleton<LicenseService>(LicenseService(licenseRemoteDataSource));
|
|
getIt.registerSingleton<WarehouseService>(WarehouseService());
|
|
getIt.registerSingleton<DashboardService>(DashboardServiceImpl(dashboardRemoteDataSource));
|
|
}
|
|
|
|
/// 로그인 수행 및 토큰 저장
|
|
static Future<String> loginAndGetToken() async {
|
|
if (_accessToken != null) {
|
|
return _accessToken!;
|
|
}
|
|
|
|
final loginRequest = LoginRequest(
|
|
email: 'admin@superport.kr',
|
|
password: 'admin123!',
|
|
);
|
|
|
|
final result = await authService.login(loginRequest);
|
|
|
|
return result.fold(
|
|
(failure) => throw Exception('로그인 실패: ${failure.message}'),
|
|
(loginResponse) {
|
|
_accessToken = loginResponse.accessToken;
|
|
apiClient.updateAuthToken(_accessToken!);
|
|
return _accessToken!;
|
|
},
|
|
);
|
|
}
|
|
|
|
/// 테스트 환경 정리
|
|
static Future<void> teardownTestEnvironment() async {
|
|
_accessToken = null;
|
|
apiClient.removeAuthToken();
|
|
// 테스트용 스토리지 정리
|
|
TestSecureStorage.clearAll();
|
|
await getIt.reset();
|
|
}
|
|
|
|
/// API 응답 로깅 헬퍼
|
|
static void logResponse(String testName, Response response) {
|
|
// === $testName ===
|
|
// Status Code: ${response.statusCode}
|
|
// Headers: ${response.headers}
|
|
// Data: ${response.data}
|
|
// =================
|
|
}
|
|
|
|
/// 에러 로깅 헬퍼
|
|
static void logError(String testName, dynamic error) {
|
|
// === $testName - ERROR ===
|
|
if (error is DioException) {
|
|
// Type: ${error.type}
|
|
// Message: ${error.message}
|
|
// Response: ${error.response?.data}
|
|
// Status Code: ${error.response?.statusCode}
|
|
} else {
|
|
// Error: $error
|
|
}
|
|
// ========================
|
|
}
|
|
}
|
|
|
|
/// 테스트 데이터 생성 헬퍼
|
|
class TestDataHelper {
|
|
static int _uniqueId = DateTime.now().millisecondsSinceEpoch;
|
|
|
|
static String generateUniqueId() {
|
|
return '${_uniqueId++}';
|
|
}
|
|
|
|
static String generateUniqueEmail() {
|
|
return 'test_${generateUniqueId()}@test.com';
|
|
}
|
|
|
|
static String generateUniqueName(String prefix) {
|
|
return '${prefix}_${generateUniqueId()}';
|
|
}
|
|
|
|
/// 테스트용 회사 데이터
|
|
static Map<String, dynamic> createTestCompanyData() {
|
|
return {
|
|
'name': generateUniqueName('Test Company'),
|
|
'business_number': '123-45-${generateUniqueId().substring(0, 5)}',
|
|
'phone': '010-${_uniqueId % 10000}-${(_uniqueId + 1) % 10000}',
|
|
'address': {
|
|
'zip_code': '12345',
|
|
'region': '서울시 강남구',
|
|
'detail_address': '테스트로 ${_uniqueId % 100}번길',
|
|
},
|
|
};
|
|
}
|
|
|
|
/// 테스트용 사용자 데이터
|
|
static Map<String, dynamic> createTestUserData({required int companyId}) {
|
|
return {
|
|
'email': generateUniqueEmail(),
|
|
'password': 'Test1234!',
|
|
'name': generateUniqueName('Test User'),
|
|
'phone': '010-${_uniqueId % 10000}-${(_uniqueId + 1) % 10000}',
|
|
'company_id': companyId,
|
|
'role': 'M', // Member
|
|
'is_active': true,
|
|
};
|
|
}
|
|
|
|
/// 테스트용 장비 데이터
|
|
static Map<String, dynamic> createTestEquipmentData({
|
|
required int companyId,
|
|
required int warehouseId,
|
|
}) {
|
|
return {
|
|
'name': generateUniqueName('Test Equipment'),
|
|
'model': 'Model-${generateUniqueId()}',
|
|
'serial_number': 'SN-${generateUniqueId()}',
|
|
'company_id': companyId,
|
|
'warehouse_id': warehouseId,
|
|
'status': 'I', // 입고
|
|
'quantity': 1,
|
|
'purchase_date': DateTime.now().toIso8601String(),
|
|
};
|
|
}
|
|
|
|
/// 테스트용 라이선스 데이터
|
|
static Map<String, dynamic> createTestLicenseData({required int companyId}) {
|
|
return {
|
|
'name': generateUniqueName('Test License'),
|
|
'product_key': 'KEY-${generateUniqueId()}',
|
|
'company_id': companyId,
|
|
'license_type': 'subscription',
|
|
'quantity': 5,
|
|
'expiry_date': DateTime.now().add(const Duration(days: 365)).toIso8601String(),
|
|
'purchase_date': DateTime.now().toIso8601String(),
|
|
};
|
|
}
|
|
|
|
/// 테스트용 창고 데이터
|
|
static Map<String, dynamic> createTestWarehouseData({required int companyId}) {
|
|
return {
|
|
'name': generateUniqueName('Test Warehouse'),
|
|
'company_id': companyId,
|
|
'location': '서울시 강남구 테스트로 ${_uniqueId % 100}',
|
|
'capacity': 1000,
|
|
'manager': generateUniqueName('Manager'),
|
|
'contact': '02-${_uniqueId % 10000}-${(_uniqueId + 1) % 10000}',
|
|
};
|
|
}
|
|
} |