import 'package:flutter_test/flutter_test.dart'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'test_result.dart'; import 'dart:math'; /// 사용자 관리 실제 API 테스트 /// /// 테스트 항목: /// 1. 사용자 목록 조회 /// 2. 사용자 생성 (관리자/일반) /// 3. 사용자 상세 조회 /// 4. 사용자 정보 수정 /// 5. 비밀번호 변경 /// 6. 사용자 권한 변경 /// 7. 사용자 비활성화/활성화 /// 8. 사용자 삭제 /// 9. 사용자 검색 /// 10. 권한별 접근 제어 테스트 Future runUserTests({ required Dio dio, required String authToken, bool verbose = false, }) async { const String baseUrl = 'http://43.201.34.104:8080/api/v1'; final Random random = Random(); final Stopwatch stopwatch = Stopwatch()..start(); int totalTests = 0; int passedTests = 0; final List failedTestNames = []; // 테스트용 사용자 데이터 final testUserData = { 'names': ['김철수', '이영희', '박민수', '정수진', '최동욱'], 'departments': ['개발팀', '영업팀', '마케팅팀', '인사팀', '운영팀'], 'positions': ['대리', '과장', '차장', '부장', '팀장'], 'emails': ['test1@superport.kr', 'test2@superport.kr', 'test3@superport.kr'], 'phones': ['010-1234-5678', '010-2345-6789', '010-3456-7890'], }; group('🧑‍💼 사용자 관리 API 테스트', () { // 생성된 사용자 ID 저장 final List createdUserIds = []; test('1. 사용자 목록 조회', () async { totalTests++; if (verbose) debugPrint('\n📋 사용자 목록 조회 테스트...'); try { final response = await dio.get( '$baseUrl/users', queryParameters: { 'page': 1, 'per_page': 20, }, ); if (response.statusCode == 200) { final users = response.data['data'] ?? []; if (verbose) { debugPrint('✅ 사용자 ${users.length}개 조회 성공'); } passedTests++; } else { failedTestNames.add('사용자 목록 조회'); if (verbose) debugPrint('❌ 사용자 목록 조회 실패: ${response.statusCode}'); } } catch (e) { failedTestNames.add('사용자 목록 조회'); if (verbose) debugPrint('❌ 사용자 목록 조회 오류: $e'); } }); test('2. 사용자 생성 (일반 사용자)', () async { totalTests++; if (verbose) debugPrint('\n➕ 일반 사용자 생성 테스트...'); final timestamp = DateTime.now().millisecondsSinceEpoch; final nameIndex = random.nextInt(testUserData['names']!.length); final deptIndex = random.nextInt(testUserData['departments']!.length); try { final newUser = { 'username': 'user_$timestamp', 'email': 'user_$timestamp@superport.kr', 'password': 'Password123!', 'name': testUserData['names']![nameIndex], 'department': testUserData['departments']![deptIndex], 'position': testUserData['positions']![random.nextInt(testUserData['positions']!.length)], 'phone': '010-${1000 + random.nextInt(9000)}-${1000 + random.nextInt(9000)}', 'role': 'user', // 일반 사용자 }; final response = await dio.post( '$baseUrl/users', data: newUser, ); if (response.statusCode == 200 || response.statusCode == 201) { final createdUser = response.data['data']; if (createdUser != null && createdUser['id'] != null) { createdUserIds.add(createdUser['id']); if (verbose) { debugPrint('✅ 일반 사용자 생성 성공: ${createdUser['name']} (${createdUser['email']})'); } passedTests++; } else { failedTestNames.add('사용자 생성 (일반)'); if (verbose) debugPrint('❌ 사용자 생성 응답에 ID가 없음'); } } else { failedTestNames.add('사용자 생성 (일반)'); if (verbose) debugPrint('❌ 사용자 생성 실패: ${response.statusCode}'); } } catch (e) { failedTestNames.add('사용자 생성 (일반)'); if (verbose) debugPrint('❌ 사용자 생성 오류: $e'); } }); test('3. 사용자 생성 (관리자)', () async { totalTests++; if (verbose) debugPrint('\n➕ 관리자 생성 테스트...'); final timestamp = DateTime.now().millisecondsSinceEpoch; try { final adminUser = { 'username': 'admin_$timestamp', 'email': 'admin_$timestamp@superport.kr', 'password': 'Admin123!@#', 'name': '관리자_$timestamp', 'department': '시스템관리팀', 'position': '팀장', 'phone': '010-9999-${1000 + random.nextInt(9000)}', 'role': 'admin', // 관리자 }; final response = await dio.post( '$baseUrl/users', data: adminUser, ); if (response.statusCode == 200 || response.statusCode == 201) { final createdUser = response.data['data']; if (createdUser != null && createdUser['id'] != null) { createdUserIds.add(createdUser['id']); if (verbose) { debugPrint('✅ 관리자 생성 성공: ${createdUser['name']}'); } passedTests++; } else { failedTestNames.add('사용자 생성 (관리자)'); if (verbose) debugPrint('❌ 관리자 생성 응답에 ID가 없음'); } } else { failedTestNames.add('사용자 생성 (관리자)'); if (verbose) debugPrint('❌ 관리자 생성 실패: ${response.statusCode}'); } } catch (e) { failedTestNames.add('사용자 생성 (관리자)'); if (verbose) debugPrint('❌ 관리자 생성 오류: $e'); } }); test('4. 사용자 상세 조회', () async { totalTests++; if (verbose) debugPrint('\n🔍 사용자 상세 조회 테스트...'); if (createdUserIds.isEmpty) { failedTestNames.add('사용자 상세 조회'); if (verbose) debugPrint('⚠️ 조회할 사용자가 없음'); return; } try { final userId = createdUserIds.first; final response = await dio.get('$baseUrl/users/$userId'); if (response.statusCode == 200) { final user = response.data['data']; if (user != null) { if (verbose) { debugPrint('✅ 사용자 상세 조회 성공: ${user['name']} (${user['email']})'); } passedTests++; } else { failedTestNames.add('사용자 상세 조회'); if (verbose) debugPrint('❌ 사용자 상세 조회 응답 비어있음'); } } else { failedTestNames.add('사용자 상세 조회'); if (verbose) debugPrint('❌ 사용자 상세 조회 실패: ${response.statusCode}'); } } catch (e) { failedTestNames.add('사용자 상세 조회'); if (verbose) debugPrint('❌ 사용자 상세 조회 오류: $e'); } }); test('5. 사용자 정보 수정', () async { totalTests++; if (verbose) debugPrint('\n✏️ 사용자 정보 수정 테스트...'); if (createdUserIds.isEmpty) { failedTestNames.add('사용자 정보 수정'); if (verbose) debugPrint('⚠️ 수정할 사용자가 없음'); return; } try { final userId = createdUserIds.first; final updatedData = { 'name': '수정된이름_${random.nextInt(1000)}', 'department': '수정된부서', 'position': '수정된직급', 'phone': '010-9999-9999', }; final response = await dio.put( '$baseUrl/users/$userId', data: updatedData, ); if (response.statusCode == 200) { if (verbose) { debugPrint('✅ 사용자 정보 수정 성공'); } passedTests++; } else { failedTestNames.add('사용자 정보 수정'); if (verbose) debugPrint('❌ 사용자 정보 수정 실패: ${response.statusCode}'); } } catch (e) { failedTestNames.add('사용자 정보 수정'); if (verbose) debugPrint('❌ 사용자 정보 수정 오류: $e'); } }); test('6. 비밀번호 변경', () async { totalTests++; if (verbose) debugPrint('\n🔐 비밀번호 변경 테스트...'); if (createdUserIds.isEmpty) { failedTestNames.add('비밀번호 변경'); if (verbose) debugPrint('⚠️ 대상 사용자가 없음'); return; } try { final userId = createdUserIds.first; final passwordData = { 'current_password': 'Password123!', 'new_password': 'NewPassword456!', 'confirm_password': 'NewPassword456!', }; final response = await dio.post( '$baseUrl/users/$userId/change-password', data: passwordData, ); if (response.statusCode == 200) { if (verbose) { debugPrint('✅ 비밀번호 변경 성공'); } passedTests++; } else { failedTestNames.add('비밀번호 변경'); if (verbose) debugPrint('❌ 비밀번호 변경 실패: ${response.statusCode}'); } } catch (e) { failedTestNames.add('비밀번호 변경'); if (verbose) debugPrint('❌ 비밀번호 변경 오류: $e'); } }); test('7. 사용자 권한 변경', () async { totalTests++; if (verbose) debugPrint('\n👤 사용자 권한 변경 테스트...'); if (createdUserIds.length < 2) { failedTestNames.add('사용자 권한 변경'); if (verbose) debugPrint('⚠️ 권한 변경할 사용자가 부족'); return; } try { final userId = createdUserIds[1]; // 두 번째 사용자 final roleData = { 'role': 'admin', // user -> admin으로 변경 }; final response = await dio.patch( '$baseUrl/users/$userId/role', data: roleData, ); if (response.statusCode == 200 || response.statusCode == 204) { if (verbose) { debugPrint('✅ 사용자 권한 변경 성공'); } passedTests++; } else { failedTestNames.add('사용자 권한 변경'); if (verbose) debugPrint('❌ 사용자 권한 변경 실패: ${response.statusCode}'); } } catch (e) { failedTestNames.add('사용자 권한 변경'); if (verbose) debugPrint('❌ 사용자 권한 변경 오류: $e'); } }); test('8. 사용자 비활성화/활성화', () async { totalTests++; if (verbose) debugPrint('\n🔄 사용자 비활성화/활성화 테스트...'); if (createdUserIds.isEmpty) { failedTestNames.add('사용자 비활성화/활성화'); if (verbose) debugPrint('⚠️ 대상 사용자가 없음'); return; } try { final userId = createdUserIds.first; // 비활성화 var response = await dio.patch( '$baseUrl/users/$userId/status', data: {'is_active': false}, ); if (response.statusCode == 200 || response.statusCode == 204) { if (verbose) debugPrint('✅ 사용자 비활성화 성공'); // 다시 활성화 response = await dio.patch( '$baseUrl/users/$userId/status', data: {'is_active': true}, ); if (response.statusCode == 200 || response.statusCode == 204) { if (verbose) debugPrint('✅ 사용자 활성화 성공'); passedTests++; } else { failedTestNames.add('사용자 비활성화/활성화'); if (verbose) debugPrint('❌ 사용자 활성화 실패: ${response.statusCode}'); } } else { failedTestNames.add('사용자 비활성화/활성화'); if (verbose) debugPrint('❌ 사용자 비활성화 실패: ${response.statusCode}'); } } catch (e) { failedTestNames.add('사용자 비활성화/활성화'); if (verbose) debugPrint('❌ 사용자 비활성화/활성화 오류: $e'); } }); test('9. 사용자 검색', () async { totalTests++; if (verbose) debugPrint('\n🔍 사용자 검색 테스트...'); try { final response = await dio.get( '$baseUrl/users/search', queryParameters: { 'q': '관리자', 'page': 1, 'per_page': 10, }, ); if (response.statusCode == 200) { final results = response.data['data'] ?? []; if (verbose) { debugPrint('✅ 사용자 검색 성공: ${results.length}개 결과'); } passedTests++; } else { failedTestNames.add('사용자 검색'); if (verbose) debugPrint('❌ 사용자 검색 실패: ${response.statusCode}'); } } catch (e) { failedTestNames.add('사용자 검색'); if (verbose) debugPrint('❌ 사용자 검색 오류: $e'); } }); test('10. 사용자 삭제', () async { totalTests++; if (verbose) debugPrint('\n🗑️ 사용자 삭제 테스트...'); if (createdUserIds.isEmpty) { failedTestNames.add('사용자 삭제'); if (verbose) debugPrint('⚠️ 삭제할 사용자가 없음'); return; } try { // 모든 생성된 사용자 삭제 for (final userId in createdUserIds) { final response = await dio.delete('$baseUrl/users/$userId'); if (response.statusCode == 200 || response.statusCode == 204) { if (verbose) debugPrint('✅ 사용자 ID $userId 삭제 성공'); } else { if (verbose) debugPrint('❌ 사용자 ID $userId 삭제 실패: ${response.statusCode}'); } } passedTests++; } catch (e) { failedTestNames.add('사용자 삭제'); if (verbose) debugPrint('❌ 사용자 삭제 오류: $e'); } }); }); stopwatch.stop(); return TestResult( name: '사용자 관리 API', totalTests: totalTests, passedTests: passedTests, failedTests: totalTests - passedTests, failedTestNames: failedTestNames, executionTime: stopwatch.elapsed, ); } void main() async { // 테스트용 Dio 인스턴스 생성 final dio = Dio(); dio.options.connectTimeout = const Duration(seconds: 10); dio.options.receiveTimeout = const Duration(seconds: 10); // 로그인 const baseUrl = 'http://43.201.34.104:8080/api/v1'; debugPrint('🔐 로그인 중...'); try { final loginResponse = await dio.post( '$baseUrl/auth/login', data: { 'email': 'admin@example.com', 'password': 'password123', }, ); final token = loginResponse.data['data']['access_token']; dio.options.headers['Authorization'] = 'Bearer $token'; debugPrint('✅ 로그인 성공\n'); // 사용자 테스트 실행 final result = await runUserTests( dio: dio, authToken: token, verbose: true, ); debugPrint('\n${result.summary}'); } catch (e) { debugPrint('❌ 로그인 실패: $e'); } finally { dio.close(); } }