Files
superport/test/integration/automated/run_equipment_in_test.dart
JiWoong Sul 731dcd816b
Some checks failed
Flutter Test & Quality Check / Test on macos-latest (push) Has been cancelled
Flutter Test & Quality Check / Test on ubuntu-latest (push) Has been cancelled
Flutter Test & Quality Check / Build APK (push) Has been cancelled
refactor: Repository 패턴 적용 및 Clean Architecture 완성
## 주요 변경사항

### 🏗️ Architecture
- Repository 패턴 전면 도입 (인터페이스/구현체 분리)
- Domain Layer에 Repository 인터페이스 정의
- Data Layer에 Repository 구현체 배치
- UseCase 의존성을 Service에서 Repository로 전환

### 📦 Dependency Injection
- GetIt 기반 DI Container 재구성 (lib/injection_container.dart)
- Repository 인터페이스와 구현체 등록
- Service와 Repository 공존 (마이그레이션 기간)

### 🔄 Migration Status
완료:
- License 모듈 (6개 UseCase)
- Warehouse Location 모듈 (5개 UseCase)

진행중:
- Auth 모듈 (2/5 UseCase)
- Company 모듈 (1/6 UseCase)

대기:
- User 모듈 (7개 UseCase)
- Equipment 모듈 (4개 UseCase)

### 🎯 Controller 통합
- 중복 Controller 제거 (with_usecase 버전)
- 단일 Controller로 통합
- UseCase 패턴 직접 적용

### 🧹 코드 정리
- 임시 파일 제거 (test_*.md, task.md)
- Node.js 아티팩트 제거 (package.json)
- 불필요한 테스트 파일 정리

###  테스트 개선
- Real API 중심 테스트 구조
- Mock 제거, 실제 API 엔드포인트 사용
- 통합 테스트 프레임워크 강화

## 기술적 영향
- 의존성 역전 원칙 적용
- 레이어 간 결합도 감소
- 테스트 용이성 향상
- 확장성 및 유지보수성 개선

## 다음 단계
1. User/Equipment 모듈 Repository 마이그레이션
2. Service Layer 점진적 제거
3. 캐싱 전략 구현
4. 성능 최적화
2025-08-11 20:14:10 +09:00

222 lines
8.1 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/foundation.dart';
import 'package:get_it/get_it.dart';
import 'package:superport/data/datasources/remote/api_client.dart';
import 'package:superport/services/equipment_service.dart';
import 'package:superport/services/company_service.dart';
import 'package:superport/services/warehouse_service.dart';
import 'package:superport/services/auth_service.dart' as auth;
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.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/warehouse_remote_datasource.dart';
import 'package:superport/data/datasources/remote/equipment_remote_datasource.dart';
import 'framework/infrastructure/test_context.dart';
import 'framework/infrastructure/report_collector.dart';
import 'framework/core/api_error_diagnostics.dart';
import 'framework/core/auto_fixer.dart';
import 'package:superport/data/models/auth/login_request.dart' as auth_models;
import 'framework/models/test_models.dart';
import 'framework/core/test_data_generator.dart';
import 'screens/equipment/equipment_in_automated_test.dart';
void main() {
late GetIt getIt;
late ApiClient apiClient;
late TestContext testContext;
late ReportCollector reportCollector;
late ApiErrorDiagnostics errorDiagnostics;
late ApiAutoFixer autoFixer;
late TestDataGenerator dataGenerator;
setUpAll(() async {
// GetIt 초기화 및 리셋
getIt = GetIt.instance;
await getIt.reset();
// 환경 변수 로드 (테스트용)
try {
await dotenv.load(fileName: '.env');
} catch (e) {
// .env 파일이 없어도 계속 진행
}
// API 클라이언트 설정
apiClient = ApiClient();
getIt.registerSingleton<ApiClient>(apiClient);
// 필요한 의존성 등록
const secureStorage = FlutterSecureStorage();
getIt.registerSingleton<FlutterSecureStorage>(secureStorage);
// DataSource 등록
getIt.registerLazySingleton<AuthRemoteDataSource>(() => AuthRemoteDataSourceImpl(apiClient));
getIt.registerLazySingleton<CompanyRemoteDataSource>(() => CompanyRemoteDataSourceImpl(apiClient));
getIt.registerLazySingleton<WarehouseRemoteDataSource>(() => WarehouseRemoteDataSourceImpl(apiClient: apiClient));
getIt.registerLazySingleton<EquipmentRemoteDataSource>(() => EquipmentRemoteDataSourceImpl());
// Service 등록
getIt.registerLazySingleton<auth.AuthService>(
() => auth.AuthServiceImpl(
getIt<AuthRemoteDataSource>(),
getIt<FlutterSecureStorage>(),
),
);
getIt.registerLazySingleton<CompanyService>(() => CompanyService(getIt<CompanyRemoteDataSource>()));
getIt.registerLazySingleton<WarehouseService>(() => WarehouseService());
getIt.registerLazySingleton<EquipmentService>(() => EquipmentService());
// 테스트 컴포넌트 초기화
testContext = TestContext();
reportCollector = ReportCollector();
errorDiagnostics = ApiErrorDiagnostics();
autoFixer = ApiAutoFixer(diagnostics: errorDiagnostics);
dataGenerator = TestDataGenerator();
// 로그인
final authService = getIt<auth.AuthService>();
try {
final loginRequest = auth_models.LoginRequest(
email: 'admin@superport.kr',
password: 'admin123!',
);
final result = await authService.login(loginRequest);
result.fold(
(failure) => debugPrint('[Setup] 로그인 실패: $failure'),
(response) => debugPrint('[Setup] 로그인 성공'),
);
} catch (e) {
debugPrint('[Setup] 로그인 실패: $e');
}
});
tearDownAll(() async {
// 테스트 후 정리
getIt.reset();
});
group('장비 입고 자동화 테스트', () {
late EquipmentInAutomatedTest equipmentInTest;
setUp(() {
equipmentInTest = EquipmentInAutomatedTest(
apiClient: apiClient,
getIt: getIt,
testContext: testContext,
errorDiagnostics: errorDiagnostics,
autoFixer: autoFixer,
dataGenerator: dataGenerator,
reportCollector: reportCollector,
);
});
test('장비 입고 전체 프로세스 실행', () async {
debugPrint('\n=== 장비 입고 자동화 테스트 시작 ===\n');
final result = await equipmentInTest.runTests();
debugPrint('\n=== 테스트 결과 ===');
debugPrint('전체 테스트: ${result.totalTests}');
debugPrint('성공: ${result.passedTests}');
debugPrint('실패: ${result.failedTests}');
debugPrint('건너뜀: ${result.skippedTests}');
// 실패한 테스트 상세 정보
if (result.failedTests > 0) {
debugPrint('\n=== 실패한 테스트 ===');
for (final failure in result.failures) {
debugPrint('- ${failure.feature}: ${failure.message}');
if (failure.stackTrace != null) {
debugPrint(' Stack Trace: ${failure.stackTrace}');
}
}
}
// 자동 수정된 항목
final fixes = reportCollector.getAutoFixes();
if (fixes.isNotEmpty) {
debugPrint('\n=== 자동 수정된 항목 ===');
for (final fix in fixes) {
debugPrint('- ${fix.errorType}: ${fix.solution}');
debugPrint(' 원인: ${fix.cause}');
}
}
// 전체 리포트 저장
final report = reportCollector.generateReport();
debugPrint('\n=== 상세 리포트 생성 완료 ===');
debugPrint('리포트 ID: ${report.reportId}');
debugPrint('실행 시간: ${report.duration.inSeconds}');
// 테스트 성공 여부 확인
// expect(result.failedTests, equals(0),
// reason: '${result.failedTests}개의 테스트가 실패했습니다');
});
test('개별 시나리오 테스트 - 정상 입고', () async {
await equipmentInTest.initializeServices();
final testData = TestData(
dataType: 'Equipment',
data: <String, dynamic>{},
metadata: <String, dynamic>{},
);
await equipmentInTest.performNormalEquipmentIn(testData);
await equipmentInTest.verifyNormalEquipmentIn(testData);
});
test('개별 시나리오 테스트 - 필수 필드 누락', () async {
await equipmentInTest.initializeServices();
final testData = TestData(
dataType: 'Equipment',
data: <String, dynamic>{},
metadata: <String, dynamic>{},
);
await equipmentInTest.performEquipmentInWithMissingFields(testData);
await equipmentInTest.verifyEquipmentInWithMissingFields(testData);
});
test('개별 시나리오 테스트 - 잘못된 참조', () async {
await equipmentInTest.initializeServices();
final testData = TestData(
dataType: 'Equipment',
data: <String, dynamic>{},
metadata: <String, dynamic>{},
);
await equipmentInTest.performEquipmentInWithInvalidReferences(testData);
await equipmentInTest.verifyEquipmentInWithInvalidReferences(testData);
});
test('개별 시나리오 테스트 - 중복 시리얼 번호', () async {
await equipmentInTest.initializeServices();
final testData = TestData(
dataType: 'Equipment',
data: <String, dynamic>{},
metadata: <String, dynamic>{},
);
await equipmentInTest.performEquipmentInWithDuplicateSerial(testData);
await equipmentInTest.verifyEquipmentInWithDuplicateSerial(testData);
});
test('개별 시나리오 테스트 - 권한 오류', () async {
await equipmentInTest.initializeServices();
final testData = TestData(
dataType: 'Equipment',
data: <String, dynamic>{},
metadata: <String, dynamic>{},
);
await equipmentInTest.performEquipmentInWithPermissionError(testData);
await equipmentInTest.verifyEquipmentInWithPermissionError(testData);
});
});
}