- 테스트 패키지 추가 (mockito, golden_toolkit, patrol 등) - 테스트 가이드 문서 작성 (TEST_GUIDE.md) - 테스트 진행 상황 문서 작성 (TEST_PROGRESS.md) - 테스트 헬퍼 클래스 구현 - test_helpers.dart: 기본 테스트 유틸리티 - mock_data_helpers.dart: Mock 데이터 생성 헬퍼 - mock_services.dart: Mock 서비스 설정 (오류 수정 완료) - simple_mock_services.dart: 간단한 Mock 서비스 - 단위 테스트 구현 - CompanyListController 테스트 - EquipmentListController 테스트 - UserListController 테스트 - Widget 테스트 구현 (CompanyListScreen) Mock 서비스 주요 수정사항: - dartz import 추가 - Either 타입 제거 (실제 서비스와 일치하도록) - 메서드 시그니처 수정 (실제 서비스 인터페이스와 일치) - Mock 데이터 생성 메서드 추가 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
614 lines
18 KiB
Dart
614 lines
18 KiB
Dart
import 'package:superport/data/models/auth/auth_user.dart';
|
|
import 'package:superport/data/models/auth/login_response.dart';
|
|
import 'package:superport/data/models/company/company_dto.dart' as company_dto;
|
|
// import 'package:superport/data/models/company/branch_dto.dart';
|
|
import 'package:superport/data/models/equipment/equipment_response.dart';
|
|
import 'package:superport/data/models/equipment/equipment_io_response.dart';
|
|
import 'package:superport/data/models/user/user_dto.dart';
|
|
import 'package:superport/data/models/license/license_dto.dart';
|
|
import 'package:superport/data/models/warehouse/warehouse_dto.dart';
|
|
import 'package:superport/data/models/common/paginated_response.dart';
|
|
import 'package:superport/models/company_model.dart';
|
|
import 'package:superport/models/address_model.dart';
|
|
import 'package:superport/models/equipment_unified_model.dart';
|
|
import 'package:superport/models/user_model.dart';
|
|
import 'package:superport/models/warehouse_location_model.dart';
|
|
import 'package:superport/models/license_model.dart';
|
|
|
|
/// 테스트용 Mock 데이터 생성 헬퍼
|
|
class MockDataHelpers {
|
|
/// Mock 사용자 생성
|
|
static AuthUser createMockUser({
|
|
int id = 1,
|
|
String username = 'testuser',
|
|
String email = 'test@example.com',
|
|
String name = '테스트 사용자',
|
|
String role = 'USER',
|
|
}) {
|
|
return AuthUser(
|
|
id: id,
|
|
username: username,
|
|
email: email,
|
|
name: name,
|
|
role: role,
|
|
);
|
|
}
|
|
|
|
/// Mock 로그인 응답 생성
|
|
static LoginResponse createMockLoginResponse({
|
|
String accessToken = 'test_access_token',
|
|
String refreshToken = 'test_refresh_token',
|
|
String tokenType = 'Bearer',
|
|
int expiresIn = 3600,
|
|
AuthUser? user,
|
|
}) {
|
|
return LoginResponse(
|
|
accessToken: accessToken,
|
|
refreshToken: refreshToken,
|
|
tokenType: tokenType,
|
|
expiresIn: expiresIn,
|
|
user: user ?? createMockUser(),
|
|
);
|
|
}
|
|
|
|
/// Mock 회사 생성
|
|
static Company createMockCompany({
|
|
int id = 1,
|
|
String name = '테스트 회사',
|
|
String? contactName,
|
|
String? contactPosition,
|
|
String? contactPhone,
|
|
String? contactEmail,
|
|
String? addressStr,
|
|
String? remark,
|
|
List<CompanyType>? companyTypes,
|
|
}) {
|
|
return Company(
|
|
id: id,
|
|
name: name,
|
|
address: Address(
|
|
zipCode: '06234',
|
|
region: addressStr ?? '서울특별시 강남구 테헤란로 123',
|
|
detailAddress: '테스트빌딩 5층',
|
|
),
|
|
contactName: contactName ?? '홍길동',
|
|
contactPosition: contactPosition ?? '대표이사',
|
|
contactPhone: contactPhone ?? '02-1234-5678',
|
|
contactEmail: contactEmail ?? 'company@test.com',
|
|
companyTypes: companyTypes ?? [CompanyType.customer],
|
|
remark: remark,
|
|
);
|
|
}
|
|
|
|
/// Mock 지점 생성
|
|
static Branch createMockBranch({
|
|
int id = 1,
|
|
int companyId = 1,
|
|
String name = '본사',
|
|
String? addressStr,
|
|
String? contactName,
|
|
String? contactPosition,
|
|
String? contactPhone,
|
|
String? contactEmail,
|
|
}) {
|
|
return Branch(
|
|
id: id,
|
|
companyId: companyId,
|
|
name: name,
|
|
address: Address(
|
|
zipCode: '06234',
|
|
region: addressStr ?? '서울특별시 강남구 테헤란로 123',
|
|
detailAddress: '테스트빌딩 5층',
|
|
),
|
|
contactName: contactName ?? '김지점',
|
|
contactPosition: contactPosition ?? '지점장',
|
|
contactPhone: contactPhone ?? '02-1234-5678',
|
|
contactEmail: contactEmail ?? 'branch@test.com',
|
|
);
|
|
}
|
|
|
|
/// Mock 장비 생성
|
|
static EquipmentResponse createMockEquipment({
|
|
int id = 1,
|
|
String equipmentNumber = 'EQ001',
|
|
String? category1,
|
|
String? category2,
|
|
String? category3,
|
|
String manufacturer = '삼성전자',
|
|
String? modelName,
|
|
String? serialNumber,
|
|
String? barcode,
|
|
DateTime? purchaseDate,
|
|
double purchasePrice = 1000000,
|
|
String status = 'AVAILABLE',
|
|
int? currentCompanyId,
|
|
int? currentBranchId,
|
|
int? warehouseLocationId,
|
|
String? remark,
|
|
String? companyName,
|
|
String? branchName,
|
|
String? warehouseName,
|
|
}) {
|
|
return EquipmentResponse(
|
|
id: id,
|
|
equipmentNumber: equipmentNumber,
|
|
category1: category1 ?? '전자기기',
|
|
category2: category2,
|
|
category3: category3,
|
|
manufacturer: manufacturer,
|
|
modelName: modelName ?? 'TEST-MODEL-001',
|
|
serialNumber: serialNumber ?? 'SN123456789',
|
|
barcode: barcode,
|
|
purchaseDate: purchaseDate ?? DateTime.now().subtract(const Duration(days: 30)),
|
|
purchasePrice: purchasePrice,
|
|
status: status,
|
|
currentCompanyId: currentCompanyId,
|
|
currentBranchId: currentBranchId,
|
|
warehouseLocationId: warehouseLocationId,
|
|
remark: remark,
|
|
createdAt: DateTime.now(),
|
|
updatedAt: DateTime.now(),
|
|
companyName: companyName,
|
|
branchName: branchName,
|
|
warehouseName: warehouseName,
|
|
);
|
|
}
|
|
|
|
/// Mock 사용자 DTO 생성
|
|
static UserDto createMockUserDto({
|
|
int id = 1,
|
|
String username = 'testuser',
|
|
String email = 'test@example.com',
|
|
String name = '테스트 사용자',
|
|
String? phone,
|
|
String role = 'staff',
|
|
bool isActive = true,
|
|
int? companyId,
|
|
int? branchId,
|
|
}) {
|
|
return UserDto(
|
|
id: id,
|
|
username: username,
|
|
email: email,
|
|
name: name,
|
|
phone: phone ?? '010-1234-5678',
|
|
role: role,
|
|
isActive: isActive,
|
|
companyId: companyId ?? 1,
|
|
branchId: branchId ?? 1,
|
|
createdAt: DateTime.now(),
|
|
updatedAt: DateTime.now(),
|
|
);
|
|
}
|
|
|
|
/// Mock 라이선스 생성
|
|
static LicenseDto createMockLicense({
|
|
int id = 1,
|
|
String licenseKey = 'TEST-LICENSE-KEY-12345',
|
|
String? productName,
|
|
String? vendor,
|
|
String? licenseType,
|
|
int? userCount,
|
|
DateTime? purchaseDate,
|
|
DateTime? expiryDate,
|
|
double? purchasePrice,
|
|
int? companyId,
|
|
int? branchId,
|
|
int? assignedUserId,
|
|
String? remark,
|
|
bool isActive = true,
|
|
}) {
|
|
return LicenseDto(
|
|
id: id,
|
|
licenseKey: licenseKey,
|
|
productName: productName ?? '테스트 라이선스',
|
|
vendor: vendor ?? '테스트 벤더',
|
|
licenseType: licenseType ?? 'SOFTWARE',
|
|
userCount: userCount ?? 10,
|
|
purchaseDate: purchaseDate ?? DateTime.now().subtract(const Duration(days: 365)),
|
|
expiryDate: expiryDate ?? DateTime.now().add(const Duration(days: 365)),
|
|
purchasePrice: purchasePrice ?? 500000,
|
|
companyId: companyId,
|
|
branchId: branchId,
|
|
assignedUserId: assignedUserId,
|
|
remark: remark,
|
|
isActive: isActive,
|
|
createdAt: DateTime.now(),
|
|
updatedAt: DateTime.now(),
|
|
);
|
|
}
|
|
|
|
/// Mock 창고 위치 생성 (WarehouseDto가 없으므로 Map 반환)
|
|
static Map<String, dynamic> createMockWarehouse({
|
|
int id = 1,
|
|
String code = 'WH001',
|
|
String name = '메인 창고',
|
|
String type = 'WAREHOUSE',
|
|
String? location,
|
|
int? capacity,
|
|
int? currentOccupancy,
|
|
String? manager,
|
|
String? contactNumber,
|
|
bool isActive = true,
|
|
String? notes,
|
|
}) {
|
|
return {
|
|
'id': id,
|
|
'code': code,
|
|
'name': name,
|
|
'type': type,
|
|
'location': location ?? '서울시 강서구 물류단지',
|
|
'capacity': capacity ?? 1000,
|
|
'currentOccupancy': currentOccupancy ?? 250,
|
|
'manager': manager ?? '김창고',
|
|
'contactNumber': contactNumber ?? '02-9876-5432',
|
|
'isActive': isActive,
|
|
'notes': notes,
|
|
'createdAt': DateTime.now().toIso8601String(),
|
|
'updatedAt': DateTime.now().toIso8601String(),
|
|
};
|
|
}
|
|
|
|
/// Mock 페이지네이션 응답 생성
|
|
static PaginatedResponse<T> createMockPaginatedResponse<T>({
|
|
required List<T> data,
|
|
int page = 1,
|
|
int size = 20,
|
|
int? totalElements,
|
|
int? totalPages,
|
|
}) {
|
|
final total = totalElements ?? data.length;
|
|
final pages = totalPages ?? ((total + size - 1) ~/ size);
|
|
|
|
return PaginatedResponse<T>(
|
|
items: data,
|
|
page: page,
|
|
size: size,
|
|
totalElements: total,
|
|
totalPages: pages,
|
|
first: page == 1,
|
|
last: page >= pages,
|
|
);
|
|
}
|
|
|
|
/// Mock 장비 목록 생성
|
|
static List<EquipmentResponse> createMockEquipmentList({int count = 10}) {
|
|
return List.generate(
|
|
count,
|
|
(index) => createMockEquipment(
|
|
id: index + 1,
|
|
equipmentNumber: 'EQ${(index + 1).toString().padLeft(3, '0')}',
|
|
category1: '전자기기',
|
|
modelName: '테스트 장비 ${index + 1}',
|
|
serialNumber: 'SN${DateTime.now().millisecondsSinceEpoch}${index}',
|
|
status: index % 3 == 0 ? 'IN_USE' : 'AVAILABLE',
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Mock UnifiedEquipment 생성
|
|
static UnifiedEquipment createMockUnifiedEquipment({
|
|
int id = 1,
|
|
int equipmentId = 1,
|
|
String manufacturer = '삼성전자',
|
|
String name = '노트북',
|
|
String category = 'IT장비',
|
|
String subCategory = '컴퓨터',
|
|
String subSubCategory = '노트북',
|
|
String? serialNumber,
|
|
int quantity = 1,
|
|
String status = 'I', // I: 입고, O: 출고, R: 대여
|
|
DateTime? date,
|
|
String? notes,
|
|
}) {
|
|
final equipment = Equipment(
|
|
id: equipmentId,
|
|
manufacturer: manufacturer,
|
|
name: name,
|
|
category: category,
|
|
subCategory: subCategory,
|
|
subSubCategory: subSubCategory,
|
|
serialNumber: serialNumber ?? 'SN${DateTime.now().millisecondsSinceEpoch}',
|
|
quantity: quantity,
|
|
inDate: date ?? DateTime.now(),
|
|
);
|
|
|
|
return UnifiedEquipment(
|
|
id: id,
|
|
equipment: equipment,
|
|
date: date ?? DateTime.now(),
|
|
status: status,
|
|
notes: notes,
|
|
);
|
|
}
|
|
|
|
/// Mock UnifiedEquipment 목록 생성
|
|
static List<UnifiedEquipment> createMockUnifiedEquipmentList({int count = 10}) {
|
|
return List.generate(
|
|
count,
|
|
(index) => createMockUnifiedEquipment(
|
|
id: index + 1,
|
|
equipmentId: index + 1,
|
|
name: '테스트 장비 ${index + 1}',
|
|
status: index % 3 == 0 ? 'O' : 'I', // 일부는 출고, 대부분은 입고 상태
|
|
serialNumber: 'SN${DateTime.now().millisecondsSinceEpoch}${index}',
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Mock 회사 목록 생성
|
|
static List<Company> createMockCompanyList({int count = 10}) {
|
|
return List.generate(
|
|
count,
|
|
(index) => createMockCompany(
|
|
id: index + 1,
|
|
name: '테스트 회사 ${index + 1}',
|
|
contactName: '담당자 ${index + 1}',
|
|
contactPosition: '대리',
|
|
contactPhone: '02-${1000 + index}-${5678 + index}',
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Mock 사용자 목록 생성
|
|
static List<UserDto> createMockUserList({int count = 10}) {
|
|
return List.generate(
|
|
count,
|
|
(index) => createMockUserDto(
|
|
id: index + 1,
|
|
username: 'user${index + 1}',
|
|
email: 'user${index + 1}@test.com',
|
|
name: '사용자 ${index + 1}',
|
|
phone: '010-${1000 + index}-${1000 + index}',
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Mock 라이선스 목록 생성
|
|
static List<LicenseDto> createMockLicenseList({int count = 10}) {
|
|
return List.generate(
|
|
count,
|
|
(index) => createMockLicense(
|
|
id: index + 1,
|
|
productName: '라이선스 ${index + 1}',
|
|
licenseKey: 'KEY-${DateTime.now().millisecondsSinceEpoch}-${index}',
|
|
licenseType: index % 2 == 0 ? 'SOFTWARE' : 'HARDWARE',
|
|
isActive: index % 4 != 0,
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Mock 창고 목록 생성
|
|
static List<dynamic> createMockWarehouseList({int count = 5}) {
|
|
return List.generate(
|
|
count,
|
|
(index) => createMockWarehouse(
|
|
id: index + 1,
|
|
code: 'WH${(index + 1).toString().padLeft(3, '0')}',
|
|
name: '창고 ${index + 1}',
|
|
type: index % 2 == 0 ? 'WAREHOUSE' : 'STORAGE',
|
|
currentOccupancy: (index + 1) * 50,
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Mock Equipment 모델 생성
|
|
static Equipment createMockEquipmentModel({
|
|
int? id,
|
|
String manufacturer = '삼성전자',
|
|
String name = '노트북',
|
|
String category = 'IT장비',
|
|
String subCategory = '컴퓨터',
|
|
String subSubCategory = '노트북',
|
|
String? serialNumber,
|
|
String? barcode,
|
|
int quantity = 1,
|
|
DateTime? inDate,
|
|
String? remark,
|
|
String? warrantyLicense,
|
|
DateTime? warrantyStartDate,
|
|
DateTime? warrantyEndDate,
|
|
}) {
|
|
return Equipment(
|
|
id: id ?? 1,
|
|
manufacturer: manufacturer,
|
|
name: name,
|
|
category: category,
|
|
subCategory: subCategory,
|
|
subSubCategory: subSubCategory,
|
|
serialNumber: serialNumber ?? 'SN${DateTime.now().millisecondsSinceEpoch}',
|
|
barcode: barcode,
|
|
quantity: quantity,
|
|
inDate: inDate ?? DateTime.now(),
|
|
remark: remark,
|
|
warrantyLicense: warrantyLicense,
|
|
warrantyStartDate: warrantyStartDate,
|
|
warrantyEndDate: warrantyEndDate,
|
|
);
|
|
}
|
|
|
|
/// Mock Equipment 모델 목록 생성
|
|
static List<Equipment> createMockEquipmentModelList({int count = 10}) {
|
|
return List.generate(
|
|
count,
|
|
(index) => createMockEquipmentModel(
|
|
id: index + 1,
|
|
name: '테스트 장비 ${index + 1}',
|
|
category: index % 2 == 0 ? 'IT장비' : '사무용품',
|
|
serialNumber: 'SN${DateTime.now().millisecondsSinceEpoch}${index}',
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Mock User 모델 생성 (UserDto가 아닌 User 모델)
|
|
static User createMockUserModel({
|
|
int? id,
|
|
int companyId = 1,
|
|
int? branchId,
|
|
String name = '테스트 사용자',
|
|
String role = 'M',
|
|
String? position,
|
|
String? email,
|
|
List<Map<String, String>>? phoneNumbers,
|
|
String? username,
|
|
bool isActive = true,
|
|
DateTime? createdAt,
|
|
DateTime? updatedAt,
|
|
}) {
|
|
return User(
|
|
id: id ?? 1,
|
|
companyId: companyId,
|
|
branchId: branchId ?? 1,
|
|
name: name,
|
|
role: role,
|
|
position: position ?? '대리',
|
|
email: email ?? 'user@test.com',
|
|
phoneNumbers: phoneNumbers ?? [{'type': '기본', 'number': '010-1234-5678'}],
|
|
username: username ?? 'testuser',
|
|
isActive: isActive,
|
|
createdAt: createdAt ?? DateTime.now(),
|
|
updatedAt: updatedAt ?? DateTime.now(),
|
|
);
|
|
}
|
|
|
|
/// Mock User 모델 목록 생성
|
|
static List<User> createMockUserModelList({int count = 10}) {
|
|
return List.generate(
|
|
count,
|
|
(index) => createMockUserModel(
|
|
id: index + 1,
|
|
name: '사용자 ${index + 1}',
|
|
username: 'user${index + 1}',
|
|
email: 'user${index + 1}@test.com',
|
|
role: index % 3 == 0 ? 'S' : 'M',
|
|
isActive: index % 5 != 0,
|
|
phoneNumbers: [{'type': '기본', 'number': '010-${1000 + index}-${1000 + index}'}],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Mock 장비 입출고 응답 생성
|
|
static EquipmentIoResponse createMockEquipmentIoResponse({
|
|
bool success = true,
|
|
String? message,
|
|
int transactionId = 1,
|
|
int equipmentId = 1,
|
|
int quantity = 1,
|
|
String transactionType = 'IN',
|
|
DateTime? transactionDate,
|
|
}) {
|
|
return EquipmentIoResponse(
|
|
success: success,
|
|
message: message ?? (success ? '장비 처리가 완료되었습니다.' : '장비 처리에 실패했습니다.'),
|
|
transactionId: transactionId,
|
|
equipmentId: equipmentId,
|
|
quantity: quantity,
|
|
transactionType: transactionType,
|
|
transactionDate: transactionDate ?? DateTime.now(),
|
|
);
|
|
}
|
|
|
|
/// Mock 창고 용량 정보 생성
|
|
static WarehouseCapacityInfo createMockWarehouseCapacityInfo({
|
|
int warehouseId = 1,
|
|
int totalCapacity = 1000,
|
|
int usedCapacity = 250,
|
|
int? availableCapacity,
|
|
double? usagePercentage,
|
|
int equipmentCount = 50,
|
|
}) {
|
|
final available = availableCapacity ?? (totalCapacity - usedCapacity);
|
|
final percentage = usagePercentage ?? (usedCapacity / totalCapacity * 100);
|
|
|
|
return WarehouseCapacityInfo(
|
|
warehouseId: warehouseId,
|
|
totalCapacity: totalCapacity,
|
|
usedCapacity: usedCapacity,
|
|
availableCapacity: available,
|
|
usagePercentage: percentage,
|
|
equipmentCount: equipmentCount,
|
|
);
|
|
}
|
|
|
|
/// Mock WarehouseLocation 생성
|
|
static WarehouseLocation createMockWarehouseLocation({
|
|
int id = 1,
|
|
String name = '메인 창고',
|
|
String? addressStr,
|
|
String? remark,
|
|
}) {
|
|
return WarehouseLocation(
|
|
id: id,
|
|
name: name,
|
|
address: Address(
|
|
zipCode: '12345',
|
|
region: addressStr ?? '서울시 강서구 물류단지',
|
|
detailAddress: '창고동 A동',
|
|
),
|
|
remark: remark,
|
|
);
|
|
}
|
|
|
|
/// Mock License 모델 생성
|
|
static License createMockLicenseModel({
|
|
int? id,
|
|
String licenseKey = 'TEST-LICENSE-KEY',
|
|
String productName = '테스트 라이선스',
|
|
String? vendor,
|
|
String? licenseType,
|
|
int? userCount,
|
|
DateTime? purchaseDate,
|
|
DateTime? expiryDate,
|
|
double? purchasePrice,
|
|
int? companyId,
|
|
int? branchId,
|
|
int? assignedUserId,
|
|
String? remark,
|
|
bool isActive = true,
|
|
}) {
|
|
return License(
|
|
id: id ?? 1,
|
|
licenseKey: licenseKey,
|
|
productName: productName,
|
|
vendor: vendor ?? '테스트 벤더',
|
|
licenseType: licenseType ?? 'SOFTWARE',
|
|
userCount: userCount ?? 10,
|
|
purchaseDate: purchaseDate ?? DateTime.now().subtract(const Duration(days: 365)),
|
|
expiryDate: expiryDate ?? DateTime.now().add(const Duration(days: 365)),
|
|
purchasePrice: purchasePrice ?? 500000,
|
|
companyId: companyId ?? 1,
|
|
branchId: branchId,
|
|
assignedUserId: assignedUserId,
|
|
remark: remark,
|
|
isActive: isActive,
|
|
createdAt: DateTime.now(),
|
|
updatedAt: DateTime.now(),
|
|
);
|
|
}
|
|
|
|
/// Mock License 모델 목록 생성
|
|
static List<License> createMockLicenseModelList({int count = 10}) {
|
|
return List.generate(
|
|
count,
|
|
(index) => createMockLicenseModel(
|
|
id: index + 1,
|
|
productName: '라이선스 ${index + 1}',
|
|
licenseKey: 'KEY-${DateTime.now().millisecondsSinceEpoch}-${index}',
|
|
licenseType: index % 2 == 0 ? 'SOFTWARE' : 'HARDWARE',
|
|
isActive: index % 4 != 0,
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Mock WarehouseLocation 목록 생성
|
|
static List<WarehouseLocation> createMockWarehouseLocationList({int count = 5}) {
|
|
return List.generate(
|
|
count,
|
|
(index) => createMockWarehouseLocation(
|
|
id: index + 1,
|
|
name: '창고 ${index + 1}',
|
|
addressStr: '서울시 ${index % 3 == 0 ? "강서구" : index % 3 == 1 ? "강남구" : "송파구"} 물류단지 ${index + 1}',
|
|
),
|
|
);
|
|
}
|
|
} |