- 모든 서비스 메서드 시그니처를 실제 구현에 맞게 수정 - 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
424 lines
9.8 KiB
Dart
424 lines
9.8 KiB
Dart
/// 화면 메타데이터
|
|
class ScreenMetadata {
|
|
final String screenName;
|
|
final Type controllerType;
|
|
final List<ApiEndpoint> relatedEndpoints;
|
|
final Map<String, dynamic> screenCapabilities;
|
|
|
|
ScreenMetadata({
|
|
required this.screenName,
|
|
required this.controllerType,
|
|
required this.relatedEndpoints,
|
|
required this.screenCapabilities,
|
|
});
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'screenName': screenName,
|
|
'controllerType': controllerType.toString(),
|
|
'relatedEndpoints': relatedEndpoints.map((e) => e.toJson()).toList(),
|
|
'screenCapabilities': screenCapabilities,
|
|
};
|
|
}
|
|
|
|
/// API 엔드포인트
|
|
class ApiEndpoint {
|
|
final String path;
|
|
final String method;
|
|
final String description;
|
|
final Map<String, dynamic>? parameters;
|
|
final Map<String, dynamic>? headers;
|
|
|
|
ApiEndpoint({
|
|
required this.path,
|
|
required this.method,
|
|
required this.description,
|
|
this.parameters,
|
|
this.headers,
|
|
});
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'path': path,
|
|
'method': method,
|
|
'description': description,
|
|
'parameters': parameters,
|
|
'headers': headers,
|
|
};
|
|
}
|
|
|
|
/// 테스트 가능한 기능
|
|
class TestableFeature {
|
|
final String featureName;
|
|
final FeatureType type;
|
|
final List<TestCase> testCases;
|
|
final Map<String, dynamic> metadata;
|
|
final Type? requiredDataType;
|
|
final Map<String, FieldConstraint>? dataConstraints;
|
|
|
|
TestableFeature({
|
|
required this.featureName,
|
|
required this.type,
|
|
required this.testCases,
|
|
required this.metadata,
|
|
this.requiredDataType,
|
|
this.dataConstraints,
|
|
});
|
|
}
|
|
|
|
/// 기능 타입
|
|
enum FeatureType {
|
|
crud,
|
|
search,
|
|
filter,
|
|
pagination,
|
|
authentication,
|
|
export,
|
|
import,
|
|
custom,
|
|
}
|
|
|
|
/// 테스트 케이스
|
|
class TestCase {
|
|
final String name;
|
|
final Future<void> Function(TestData data) execute;
|
|
final Future<void> Function(TestData data) verify;
|
|
final Future<void> Function(TestData data)? setup;
|
|
final Future<void> Function(TestData data)? teardown;
|
|
final Map<String, dynamic>? metadata;
|
|
|
|
TestCase({
|
|
required this.name,
|
|
required this.execute,
|
|
required this.verify,
|
|
this.setup,
|
|
this.teardown,
|
|
this.metadata,
|
|
});
|
|
}
|
|
|
|
/// 테스트 데이터
|
|
class TestData {
|
|
final String dataType;
|
|
final dynamic data;
|
|
final Map<String, dynamic> metadata;
|
|
|
|
TestData({
|
|
required this.dataType,
|
|
required this.data,
|
|
required this.metadata,
|
|
});
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'dataType': dataType,
|
|
'data': data is Map || data is List ? data : data?.toJson() ?? {},
|
|
'metadata': metadata,
|
|
};
|
|
}
|
|
|
|
/// 데이터 요구사항
|
|
class DataRequirement {
|
|
final Type dataType;
|
|
final Map<String, FieldConstraint> constraints;
|
|
final List<DataRelationship> relationships;
|
|
final int quantity;
|
|
|
|
DataRequirement({
|
|
required this.dataType,
|
|
required this.constraints,
|
|
required this.relationships,
|
|
required this.quantity,
|
|
});
|
|
}
|
|
|
|
/// 필드 제약조건
|
|
class FieldConstraint {
|
|
final bool required;
|
|
final bool nullable;
|
|
final int? minLength;
|
|
final int? maxLength;
|
|
final num? minValue;
|
|
final num? maxValue;
|
|
final String? pattern;
|
|
final List<dynamic>? allowedValues;
|
|
final String? defaultValue;
|
|
|
|
FieldConstraint({
|
|
this.required = true,
|
|
this.nullable = false,
|
|
this.minLength,
|
|
this.maxLength,
|
|
this.minValue,
|
|
this.maxValue,
|
|
this.pattern,
|
|
this.allowedValues,
|
|
this.defaultValue,
|
|
});
|
|
}
|
|
|
|
/// 데이터 관계
|
|
class DataRelationship {
|
|
final String name;
|
|
final Type targetType;
|
|
final RelationType type;
|
|
final String targetId;
|
|
final int? count;
|
|
final Map<String, FieldConstraint>? constraints;
|
|
|
|
DataRelationship({
|
|
required this.name,
|
|
required this.targetType,
|
|
required this.type,
|
|
required this.targetId,
|
|
this.count,
|
|
this.constraints,
|
|
});
|
|
}
|
|
|
|
/// 관계 타입
|
|
enum RelationType {
|
|
oneToOne,
|
|
oneToMany,
|
|
manyToMany,
|
|
}
|
|
|
|
/// 생성 전략
|
|
class GenerationStrategy {
|
|
final Type dataType;
|
|
final List<FieldGeneration> fields;
|
|
final List<DataRelationship> relationships;
|
|
final Map<String, dynamic> constraints;
|
|
final int? quantity;
|
|
|
|
GenerationStrategy({
|
|
required this.dataType,
|
|
required this.fields,
|
|
required this.relationships,
|
|
required this.constraints,
|
|
this.quantity,
|
|
});
|
|
}
|
|
|
|
/// 필드 생성 전략
|
|
class FieldGeneration {
|
|
final String fieldName;
|
|
final Type valueType;
|
|
final String strategy;
|
|
final String? prefix;
|
|
final String? format;
|
|
final List<dynamic>? pool;
|
|
final String? relatedTo;
|
|
final List<String>? values;
|
|
final dynamic value;
|
|
|
|
FieldGeneration({
|
|
required this.fieldName,
|
|
required this.valueType,
|
|
required this.strategy,
|
|
this.prefix,
|
|
this.format,
|
|
this.pool,
|
|
this.relatedTo,
|
|
this.values,
|
|
this.value,
|
|
});
|
|
}
|
|
|
|
/// 필드 정의
|
|
class FieldDefinition {
|
|
final String name;
|
|
final FieldType type;
|
|
final dynamic Function() generator;
|
|
final bool required;
|
|
final bool nullable;
|
|
|
|
FieldDefinition({
|
|
required this.name,
|
|
required this.type,
|
|
required this.generator,
|
|
this.required = true,
|
|
this.nullable = false,
|
|
});
|
|
}
|
|
|
|
/// 필드 타입
|
|
enum FieldType {
|
|
string,
|
|
integer,
|
|
double,
|
|
boolean,
|
|
dateTime,
|
|
date,
|
|
time,
|
|
object,
|
|
array,
|
|
}
|
|
|
|
/// 테스트 결과
|
|
class TestResult {
|
|
final String screenName;
|
|
final DateTime startTime;
|
|
DateTime? endTime;
|
|
final List<FeatureTestResult> featureResults = [];
|
|
final List<TestError> errors = [];
|
|
final Map<String, dynamic> metrics = {};
|
|
|
|
TestResult({
|
|
required this.screenName,
|
|
required this.startTime,
|
|
this.endTime,
|
|
});
|
|
|
|
bool get success => errors.isEmpty && featureResults.every((r) => r.success);
|
|
bool get passed => success; // 호환성을 위한 별칭
|
|
|
|
Duration get duration => endTime != null
|
|
? endTime!.difference(startTime)
|
|
: Duration.zero;
|
|
|
|
// 테스트 카운트 관련 getter들
|
|
int get totalTests => featureResults
|
|
.expand((r) => r.testCaseResults)
|
|
.length;
|
|
|
|
int get passedTests => featureResults
|
|
.expand((r) => r.testCaseResults)
|
|
.where((r) => r.success)
|
|
.length;
|
|
|
|
int get failedTests => totalTests - passedTests;
|
|
|
|
void calculateMetrics() {
|
|
metrics['totalFeatures'] = featureResults.length;
|
|
metrics['successfulFeatures'] = featureResults.where((r) => r.success).length;
|
|
metrics['failedFeatures'] = featureResults.where((r) => !r.success).length;
|
|
metrics['totalTestCases'] = featureResults
|
|
.expand((r) => r.testCaseResults)
|
|
.length;
|
|
metrics['successfulTestCases'] = featureResults
|
|
.expand((r) => r.testCaseResults)
|
|
.where((r) => r.success)
|
|
.length;
|
|
metrics['averageDuration'] = _calculateAverageDuration();
|
|
}
|
|
|
|
double _calculateAverageDuration() {
|
|
final allDurations = featureResults
|
|
.expand((r) => r.testCaseResults)
|
|
.map((r) => r.duration.inMilliseconds);
|
|
|
|
if (allDurations.isEmpty) return 0;
|
|
|
|
return allDurations.reduce((a, b) => a + b) / allDurations.length;
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'screenName': screenName,
|
|
'success': success,
|
|
'startTime': startTime.toIso8601String(),
|
|
'endTime': endTime?.toIso8601String(),
|
|
'duration': duration.inMilliseconds,
|
|
'featureResults': featureResults.map((r) => r.toJson()).toList(),
|
|
'errors': errors.map((e) => e.toJson()).toList(),
|
|
'metrics': metrics,
|
|
};
|
|
}
|
|
|
|
/// 기능 테스트 결과
|
|
class FeatureTestResult {
|
|
final String featureName;
|
|
final DateTime startTime;
|
|
DateTime? endTime;
|
|
final List<TestCaseResult> testCaseResults = [];
|
|
final Map<String, dynamic> metrics = {};
|
|
|
|
FeatureTestResult({
|
|
required this.featureName,
|
|
required this.startTime,
|
|
this.endTime,
|
|
});
|
|
|
|
bool get success => testCaseResults.every((r) => r.success);
|
|
|
|
Duration get duration => endTime != null
|
|
? endTime!.difference(startTime)
|
|
: Duration.zero;
|
|
|
|
void calculateMetrics() {
|
|
metrics['totalTestCases'] = testCaseResults.length;
|
|
metrics['successfulTestCases'] = testCaseResults.where((r) => r.success).length;
|
|
metrics['failedTestCases'] = testCaseResults.where((r) => !r.success).length;
|
|
metrics['averageDuration'] = _calculateAverageDuration();
|
|
}
|
|
|
|
double _calculateAverageDuration() {
|
|
if (testCaseResults.isEmpty) return 0;
|
|
|
|
final totalMs = testCaseResults
|
|
.map((r) => r.duration.inMilliseconds)
|
|
.reduce((a, b) => a + b);
|
|
|
|
return totalMs / testCaseResults.length;
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'featureName': featureName,
|
|
'success': success,
|
|
'startTime': startTime.toIso8601String(),
|
|
'endTime': endTime?.toIso8601String(),
|
|
'duration': duration.inMilliseconds,
|
|
'testCaseResults': testCaseResults.map((r) => r.toJson()).toList(),
|
|
'metrics': metrics,
|
|
};
|
|
}
|
|
|
|
/// 테스트 케이스 결과
|
|
class TestCaseResult {
|
|
final String testCaseName;
|
|
final bool success;
|
|
final Duration duration;
|
|
final String? error;
|
|
final StackTrace? stackTrace;
|
|
final Map<String, dynamic>? metadata;
|
|
|
|
TestCaseResult({
|
|
required this.testCaseName,
|
|
required this.success,
|
|
required this.duration,
|
|
this.error,
|
|
this.stackTrace,
|
|
this.metadata,
|
|
});
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'testCaseName': testCaseName,
|
|
'success': success,
|
|
'duration': duration.inMilliseconds,
|
|
'error': error,
|
|
'stackTrace': stackTrace?.toString(),
|
|
'metadata': metadata,
|
|
};
|
|
}
|
|
|
|
/// 테스트 에러
|
|
class TestError {
|
|
final String message;
|
|
final StackTrace? stackTrace;
|
|
final String? feature;
|
|
final DateTime timestamp;
|
|
final Map<String, dynamic>? context;
|
|
|
|
TestError({
|
|
required this.message,
|
|
this.stackTrace,
|
|
this.feature,
|
|
required this.timestamp,
|
|
this.context,
|
|
});
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'message': message,
|
|
'stackTrace': stackTrace?.toString(),
|
|
'feature': feature,
|
|
'timestamp': timestamp.toIso8601String(),
|
|
'context': context,
|
|
};
|
|
} |