test: 통합 테스트 오류 및 경고 수정
- 모든 서비스 메서드 시그니처를 실제 구현에 맞게 수정 - 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
This commit is contained in:
529
test/integration/automated/framework/models/error_models.dart
Normal file
529
test/integration/automated/framework/models/error_models.dart
Normal file
@@ -0,0 +1,529 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
/// 에러 타입
|
||||
enum ErrorType {
|
||||
/// 필수 필드 누락
|
||||
missingRequiredField,
|
||||
|
||||
/// 잘못된 참조
|
||||
invalidReference,
|
||||
|
||||
/// 중복 데이터
|
||||
duplicateData,
|
||||
|
||||
/// 권한 부족
|
||||
permissionDenied,
|
||||
|
||||
/// 유효성 검증 실패
|
||||
validation,
|
||||
|
||||
/// 서버 에러
|
||||
serverError,
|
||||
|
||||
/// 네트워크 에러
|
||||
networkError,
|
||||
|
||||
/// 알 수 없는 에러
|
||||
unknown,
|
||||
}
|
||||
|
||||
/// API 에러 타입 분류
|
||||
enum ApiErrorType {
|
||||
/// 인증 관련 에러 (401, 403)
|
||||
authentication,
|
||||
|
||||
/// 유효성 검증 에러 (400)
|
||||
validation,
|
||||
|
||||
/// 리소스 찾기 실패 (404)
|
||||
notFound,
|
||||
|
||||
/// 서버 내부 에러 (500)
|
||||
serverError,
|
||||
|
||||
/// 네트워크 연결 에러
|
||||
networkConnection,
|
||||
|
||||
/// 타임아웃 에러
|
||||
timeout,
|
||||
|
||||
/// 요청 취소
|
||||
cancelled,
|
||||
|
||||
/// 속도 제한
|
||||
rateLimit,
|
||||
|
||||
/// 알 수 없는 에러
|
||||
unknown,
|
||||
}
|
||||
|
||||
/// API 에러 진단 결과
|
||||
class ErrorDiagnosis {
|
||||
/// API 에러 타입
|
||||
final ApiErrorType type;
|
||||
|
||||
/// 일반 에러 타입
|
||||
final ErrorType errorType;
|
||||
|
||||
/// 에러 설명
|
||||
final String description;
|
||||
|
||||
/// 에러 컨텍스트 정보
|
||||
final Map<String, dynamic> context;
|
||||
|
||||
/// 진단 신뢰도 (0.0 ~ 1.0)
|
||||
final double confidence;
|
||||
|
||||
/// 영향받은 API 엔드포인트
|
||||
final List<String> affectedEndpoints;
|
||||
|
||||
/// 서버 에러 코드 (있는 경우)
|
||||
final String? serverErrorCode;
|
||||
|
||||
/// 누락된 필드 목록
|
||||
final List<String>? missingFields;
|
||||
|
||||
/// 타입 불일치 필드 정보
|
||||
final Map<String, TypeMismatchInfo>? typeMismatches;
|
||||
|
||||
/// 원본 에러 메시지
|
||||
final String? originalMessage;
|
||||
|
||||
/// 에러 발생 시간
|
||||
final DateTime timestamp;
|
||||
|
||||
ErrorDiagnosis({
|
||||
required this.type,
|
||||
required this.errorType,
|
||||
required this.description,
|
||||
required this.context,
|
||||
required this.confidence,
|
||||
required this.affectedEndpoints,
|
||||
this.serverErrorCode,
|
||||
this.missingFields,
|
||||
this.typeMismatches,
|
||||
this.originalMessage,
|
||||
DateTime? timestamp,
|
||||
}) : timestamp = timestamp ?? DateTime.now();
|
||||
|
||||
/// JSON으로 변환
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'type': type.toString(),
|
||||
'errorType': errorType.toString(),
|
||||
'description': description,
|
||||
'context': context,
|
||||
'confidence': confidence,
|
||||
'affectedEndpoints': affectedEndpoints,
|
||||
'serverErrorCode': serverErrorCode,
|
||||
'missingFields': missingFields,
|
||||
'typeMismatches': typeMismatches?.map(
|
||||
(key, value) => MapEntry(key, value.toJson()),
|
||||
),
|
||||
'originalMessage': originalMessage,
|
||||
'timestamp': timestamp.toIso8601String(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// 타입 불일치 정보
|
||||
class TypeMismatchInfo {
|
||||
/// 필드 이름
|
||||
final String fieldName;
|
||||
|
||||
/// 예상 타입
|
||||
final String expectedType;
|
||||
|
||||
/// 실제 타입
|
||||
final String actualType;
|
||||
|
||||
/// 실제 값
|
||||
final dynamic actualValue;
|
||||
|
||||
TypeMismatchInfo({
|
||||
required this.fieldName,
|
||||
required this.expectedType,
|
||||
required this.actualType,
|
||||
this.actualValue,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'fieldName': fieldName,
|
||||
'expectedType': expectedType,
|
||||
'actualType': actualType,
|
||||
'actualValue': actualValue,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// 수정 제안 타입
|
||||
enum FixType {
|
||||
/// 토큰 갱신
|
||||
refreshToken,
|
||||
|
||||
/// 필드 추가
|
||||
addMissingField,
|
||||
|
||||
/// 타입 변환
|
||||
convertType,
|
||||
|
||||
/// 재시도
|
||||
retry,
|
||||
|
||||
/// 데이터 수정
|
||||
modifyData,
|
||||
|
||||
/// 권한 요청
|
||||
requestPermission,
|
||||
|
||||
/// 엔드포인트 변경
|
||||
endpointSwitch,
|
||||
|
||||
/// 설정 변경
|
||||
configuration,
|
||||
|
||||
/// 수동 개입 필요
|
||||
manualIntervention,
|
||||
}
|
||||
|
||||
/// 수정 제안
|
||||
class FixSuggestion {
|
||||
/// 수정 ID
|
||||
final String fixId;
|
||||
|
||||
/// 수정 타입
|
||||
final FixType type;
|
||||
|
||||
/// 수정 설명
|
||||
final String description;
|
||||
|
||||
/// 수정 작업 목록
|
||||
final List<FixAction> actions;
|
||||
|
||||
/// 성공 확률 (0.0 ~ 1.0)
|
||||
final double successProbability;
|
||||
|
||||
/// 자동 수정 가능 여부
|
||||
final bool isAutoFixable;
|
||||
|
||||
/// 예상 소요 시간 (밀리초)
|
||||
final int? estimatedDuration;
|
||||
|
||||
FixSuggestion({
|
||||
required this.fixId,
|
||||
required this.type,
|
||||
required this.description,
|
||||
required this.actions,
|
||||
required this.successProbability,
|
||||
required this.isAutoFixable,
|
||||
this.estimatedDuration,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'fixId': fixId,
|
||||
'type': type.toString(),
|
||||
'description': description,
|
||||
'actions': actions.map((a) => a.toJson()).toList(),
|
||||
'successProbability': successProbability,
|
||||
'isAutoFixable': isAutoFixable,
|
||||
'estimatedDuration': estimatedDuration,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// 수정 작업
|
||||
class FixAction {
|
||||
/// 작업 타입
|
||||
final FixActionType type;
|
||||
|
||||
/// 작업 타입 문자열 (하위 호환성)
|
||||
final String actionType;
|
||||
|
||||
/// 대상
|
||||
final String target;
|
||||
|
||||
/// 작업 파라미터
|
||||
final Map<String, dynamic> parameters;
|
||||
|
||||
/// 작업 설명
|
||||
final String? description;
|
||||
|
||||
FixAction({
|
||||
required this.type,
|
||||
required this.actionType,
|
||||
required this.target,
|
||||
required this.parameters,
|
||||
this.description,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'type': type.toString(),
|
||||
'actionType': actionType,
|
||||
'target': target,
|
||||
'parameters': parameters,
|
||||
'description': description,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// 수정 결과
|
||||
class FixResult {
|
||||
/// 수정 ID
|
||||
final String fixId;
|
||||
|
||||
/// 성공 여부
|
||||
final bool success;
|
||||
|
||||
/// 실행된 작업 목록
|
||||
final List<FixAction> executedActions;
|
||||
|
||||
/// 실행 시간
|
||||
final DateTime executedAt;
|
||||
|
||||
/// 소요 시간 (밀리초)
|
||||
final int duration;
|
||||
|
||||
/// 에러 (실패 시)
|
||||
final String? error;
|
||||
|
||||
/// 추가 정보
|
||||
final Map<String, dynamic>? additionalInfo;
|
||||
|
||||
FixResult({
|
||||
required this.fixId,
|
||||
required this.success,
|
||||
required this.executedActions,
|
||||
required this.executedAt,
|
||||
required this.duration,
|
||||
this.error,
|
||||
this.additionalInfo,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'fixId': fixId,
|
||||
'success': success,
|
||||
'executedActions': executedActions.map((a) => a.toJson()).toList(),
|
||||
'executedAt': executedAt.toIso8601String(),
|
||||
'duration': duration,
|
||||
'error': error,
|
||||
'additionalInfo': additionalInfo,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// 에러 패턴 (학습용)
|
||||
class ErrorPattern {
|
||||
/// 패턴 ID
|
||||
final String patternId;
|
||||
|
||||
/// 에러 타입
|
||||
final ApiErrorType errorType;
|
||||
|
||||
/// 패턴 매칭 규칙
|
||||
final Map<String, dynamic> matchingRules;
|
||||
|
||||
/// 성공한 수정 전략
|
||||
final List<FixSuggestion> successfulFixes;
|
||||
|
||||
/// 발생 횟수
|
||||
final int occurrenceCount;
|
||||
|
||||
/// 마지막 발생 시간
|
||||
final DateTime lastOccurred;
|
||||
|
||||
/// 학습 신뢰도
|
||||
final double confidence;
|
||||
|
||||
ErrorPattern({
|
||||
required this.patternId,
|
||||
required this.errorType,
|
||||
required this.matchingRules,
|
||||
required this.successfulFixes,
|
||||
required this.occurrenceCount,
|
||||
required this.lastOccurred,
|
||||
required this.confidence,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'patternId': patternId,
|
||||
'errorType': errorType.toString(),
|
||||
'matchingRules': matchingRules,
|
||||
'successfulFixes': successfulFixes.map((f) => f.toJson()).toList(),
|
||||
'occurrenceCount': occurrenceCount,
|
||||
'lastOccurred': lastOccurred.toIso8601String(),
|
||||
'confidence': confidence,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// API 에러 정보
|
||||
class ApiError {
|
||||
/// 원본 에러 (optional)
|
||||
final DioException? originalError;
|
||||
|
||||
/// 요청 URL
|
||||
final String requestUrl;
|
||||
|
||||
/// 요청 메서드
|
||||
final String requestMethod;
|
||||
|
||||
/// 요청 헤더
|
||||
final Map<String, dynamic>? requestHeaders;
|
||||
|
||||
/// 요청 바디
|
||||
final dynamic requestBody;
|
||||
|
||||
/// 응답 상태 코드
|
||||
final int? statusCode;
|
||||
|
||||
/// 응답 바디
|
||||
final dynamic responseBody;
|
||||
|
||||
/// 에러 메시지
|
||||
final String? message;
|
||||
|
||||
/// API 엔드포인트
|
||||
final String? endpoint;
|
||||
|
||||
/// HTTP 메서드
|
||||
final String? method;
|
||||
|
||||
/// 에러 발생 시간
|
||||
final DateTime timestamp;
|
||||
|
||||
ApiError({
|
||||
this.originalError,
|
||||
required this.requestUrl,
|
||||
required this.requestMethod,
|
||||
this.requestHeaders,
|
||||
this.requestBody,
|
||||
this.statusCode,
|
||||
this.responseBody,
|
||||
this.message,
|
||||
this.endpoint,
|
||||
this.method,
|
||||
DateTime? timestamp,
|
||||
}) : timestamp = timestamp ?? DateTime.now();
|
||||
|
||||
/// DioException으로부터 생성
|
||||
factory ApiError.fromDioException(DioException error) {
|
||||
return ApiError(
|
||||
originalError: error,
|
||||
requestUrl: error.requestOptions.uri.toString(),
|
||||
requestMethod: error.requestOptions.method,
|
||||
requestHeaders: error.requestOptions.headers,
|
||||
requestBody: error.requestOptions.data,
|
||||
statusCode: error.response?.statusCode,
|
||||
responseBody: error.response?.data,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'requestUrl': requestUrl,
|
||||
'requestMethod': requestMethod,
|
||||
'requestHeaders': requestHeaders,
|
||||
'requestBody': requestBody,
|
||||
'statusCode': statusCode,
|
||||
'responseBody': responseBody,
|
||||
'timestamp': timestamp.toIso8601String(),
|
||||
'errorType': originalError?.type.toString(),
|
||||
'errorMessage': message ?? originalError?.message,
|
||||
'endpoint': endpoint,
|
||||
'method': method,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Fix 액션 타입
|
||||
enum FixActionType {
|
||||
/// 필드 업데이트
|
||||
updateField,
|
||||
|
||||
/// 누락된 리소스 생성
|
||||
createMissingResource,
|
||||
|
||||
/// 재시도 with 지연
|
||||
retryWithDelay,
|
||||
|
||||
/// 데이터 타입 변환
|
||||
convertDataType,
|
||||
|
||||
/// 권한 변경
|
||||
changePermission,
|
||||
|
||||
/// 알수 없음
|
||||
unknown,
|
||||
}
|
||||
|
||||
/// 근본 원인 분석 결과
|
||||
class RootCause {
|
||||
/// 원인 타입
|
||||
final String causeType;
|
||||
|
||||
/// 원인 설명
|
||||
final String description;
|
||||
|
||||
/// 증거 목록
|
||||
final List<String> evidence;
|
||||
|
||||
/// 연관된 진단 결과
|
||||
final ErrorDiagnosis diagnosis;
|
||||
|
||||
/// 권장 수정 방법
|
||||
final List<FixSuggestion> recommendedFixes;
|
||||
|
||||
RootCause({
|
||||
required this.causeType,
|
||||
required this.description,
|
||||
required this.evidence,
|
||||
required this.diagnosis,
|
||||
required this.recommendedFixes,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'causeType': causeType,
|
||||
'description': description,
|
||||
'evidence': evidence,
|
||||
'diagnosis': diagnosis.toJson(),
|
||||
'recommendedFixes': recommendedFixes.map((f) => f.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// 변경 사항
|
||||
class Change {
|
||||
/// 변경 타입
|
||||
final String type;
|
||||
|
||||
/// 변경 전 값
|
||||
final dynamic before;
|
||||
|
||||
/// 변경 후 값
|
||||
final dynamic after;
|
||||
|
||||
/// 변경 대상
|
||||
final String target;
|
||||
|
||||
Change({
|
||||
required this.type,
|
||||
this.before,
|
||||
this.after,
|
||||
required this.target,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'type': type,
|
||||
'before': before,
|
||||
'after': after,
|
||||
'target': target,
|
||||
};
|
||||
}
|
||||
}
|
||||
606
test/integration/automated/framework/models/report_models.dart
Normal file
606
test/integration/automated/framework/models/report_models.dart
Normal file
@@ -0,0 +1,606 @@
|
||||
/// 테스트 리포트
|
||||
class TestReport {
|
||||
final String reportId;
|
||||
final DateTime generatedAt;
|
||||
final ReportType type;
|
||||
final List<ScreenTestReport> screenReports;
|
||||
final TestSummary summary;
|
||||
final List<ErrorAnalysis> errorAnalyses;
|
||||
final List<PerformanceMetric> performanceMetrics;
|
||||
final Map<String, dynamic> metadata;
|
||||
|
||||
TestReport({
|
||||
required this.reportId,
|
||||
required this.generatedAt,
|
||||
required this.type,
|
||||
required this.screenReports,
|
||||
required this.summary,
|
||||
required this.errorAnalyses,
|
||||
required this.performanceMetrics,
|
||||
required this.metadata,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'reportId': reportId,
|
||||
'generatedAt': generatedAt.toIso8601String(),
|
||||
'type': type.toString(),
|
||||
'screenReports': screenReports.map((r) => r.toJson()).toList(),
|
||||
'summary': summary.toJson(),
|
||||
'errorAnalyses': errorAnalyses.map((e) => e.toJson()).toList(),
|
||||
'performanceMetrics': performanceMetrics.map((m) => m.toJson()).toList(),
|
||||
'metadata': metadata,
|
||||
};
|
||||
}
|
||||
|
||||
/// 리포트 타입
|
||||
enum ReportType {
|
||||
full,
|
||||
summary,
|
||||
error,
|
||||
performance,
|
||||
custom,
|
||||
}
|
||||
|
||||
/// 기능 타입
|
||||
enum FeatureType {
|
||||
crud,
|
||||
navigation,
|
||||
validation,
|
||||
authentication,
|
||||
dataSync,
|
||||
ui,
|
||||
performance,
|
||||
custom,
|
||||
screen,
|
||||
}
|
||||
|
||||
/// 에러 타입
|
||||
enum ErrorType {
|
||||
runtime,
|
||||
network,
|
||||
validation,
|
||||
authentication,
|
||||
timeout,
|
||||
assertion,
|
||||
ui,
|
||||
unknown,
|
||||
}
|
||||
|
||||
/// 근본 원인
|
||||
class RootCause {
|
||||
final String category;
|
||||
final String description;
|
||||
final double confidence;
|
||||
final Map<String, dynamic>? evidence;
|
||||
|
||||
RootCause({
|
||||
required this.category,
|
||||
required this.description,
|
||||
required this.confidence,
|
||||
this.evidence,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'category': category,
|
||||
'description': description,
|
||||
'confidence': confidence,
|
||||
'evidence': evidence,
|
||||
};
|
||||
}
|
||||
|
||||
/// 수정 제안
|
||||
class FixSuggestion {
|
||||
final String title;
|
||||
final String description;
|
||||
final String code;
|
||||
final double priority;
|
||||
final bool isAutoFixable;
|
||||
|
||||
FixSuggestion({
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.code,
|
||||
required this.priority,
|
||||
required this.isAutoFixable,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'title': title,
|
||||
'description': description,
|
||||
'code': code,
|
||||
'priority': priority,
|
||||
'isAutoFixable': isAutoFixable,
|
||||
};
|
||||
}
|
||||
|
||||
/// 화면별 테스트 리포트
|
||||
class ScreenTestReport {
|
||||
final String screenName;
|
||||
final TestResult testResult;
|
||||
final List<FeatureReport> featureReports;
|
||||
final Map<String, dynamic> coverage;
|
||||
final List<String> recommendations;
|
||||
|
||||
ScreenTestReport({
|
||||
required this.screenName,
|
||||
required this.testResult,
|
||||
required this.featureReports,
|
||||
required this.coverage,
|
||||
required this.recommendations,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'screenName': screenName,
|
||||
'testResult': testResult.toJson(),
|
||||
'featureReports': featureReports.map((r) => r.toJson()).toList(),
|
||||
'coverage': coverage,
|
||||
'recommendations': recommendations,
|
||||
};
|
||||
}
|
||||
|
||||
/// 기능별 리포트
|
||||
class FeatureReport {
|
||||
final String featureName;
|
||||
final FeatureType featureType;
|
||||
final bool success;
|
||||
final int totalTests;
|
||||
final int passedTests;
|
||||
final int failedTests;
|
||||
final Duration totalDuration;
|
||||
final List<TestCaseReport> testCaseReports;
|
||||
|
||||
FeatureReport({
|
||||
required this.featureName,
|
||||
required this.featureType,
|
||||
required this.success,
|
||||
required this.totalTests,
|
||||
required this.passedTests,
|
||||
required this.failedTests,
|
||||
required this.totalDuration,
|
||||
required this.testCaseReports,
|
||||
});
|
||||
|
||||
double get successRate => totalTests > 0 ? passedTests / totalTests : 0;
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'featureName': featureName,
|
||||
'featureType': featureType.toString(),
|
||||
'success': success,
|
||||
'totalTests': totalTests,
|
||||
'passedTests': passedTests,
|
||||
'failedTests': failedTests,
|
||||
'successRate': successRate,
|
||||
'totalDuration': totalDuration.inMilliseconds,
|
||||
'testCaseReports': testCaseReports.map((r) => r.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
/// 테스트 케이스 리포트
|
||||
class TestCaseReport {
|
||||
final String testCaseName;
|
||||
final bool success;
|
||||
final Duration duration;
|
||||
final String? errorMessage;
|
||||
final String? stackTrace;
|
||||
final List<TestStep> steps;
|
||||
final Map<String, dynamic>? additionalInfo;
|
||||
|
||||
TestCaseReport({
|
||||
required this.testCaseName,
|
||||
required this.success,
|
||||
required this.duration,
|
||||
this.errorMessage,
|
||||
this.stackTrace,
|
||||
required this.steps,
|
||||
this.additionalInfo,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'testCaseName': testCaseName,
|
||||
'success': success,
|
||||
'duration': duration.inMilliseconds,
|
||||
'errorMessage': errorMessage,
|
||||
'stackTrace': stackTrace,
|
||||
'steps': steps.map((s) => s.toJson()).toList(),
|
||||
'additionalInfo': additionalInfo,
|
||||
};
|
||||
}
|
||||
|
||||
/// 테스트 단계
|
||||
class TestStep {
|
||||
final String stepName;
|
||||
final StepType type;
|
||||
final bool success;
|
||||
final String? description;
|
||||
final Map<String, dynamic>? data;
|
||||
final DateTime timestamp;
|
||||
|
||||
TestStep({
|
||||
required this.stepName,
|
||||
required this.type,
|
||||
required this.success,
|
||||
this.description,
|
||||
this.data,
|
||||
required this.timestamp,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'stepName': stepName,
|
||||
'type': type.toString(),
|
||||
'success': success,
|
||||
'description': description,
|
||||
'data': data,
|
||||
'timestamp': timestamp.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
/// 단계 타입
|
||||
enum StepType {
|
||||
setup,
|
||||
action,
|
||||
verification,
|
||||
teardown,
|
||||
}
|
||||
|
||||
/// 테스트 요약
|
||||
class TestSummary {
|
||||
final int totalScreens;
|
||||
final int totalFeatures;
|
||||
final int totalTestCases;
|
||||
final int passedTestCases;
|
||||
final int failedTestCases;
|
||||
final int skippedTestCases;
|
||||
final Duration totalDuration;
|
||||
final double overallSuccessRate;
|
||||
final DateTime startTime;
|
||||
final DateTime endTime;
|
||||
|
||||
TestSummary({
|
||||
required this.totalScreens,
|
||||
required this.totalFeatures,
|
||||
required this.totalTestCases,
|
||||
required this.passedTestCases,
|
||||
required this.failedTestCases,
|
||||
required this.skippedTestCases,
|
||||
required this.totalDuration,
|
||||
required this.overallSuccessRate,
|
||||
required this.startTime,
|
||||
required this.endTime,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'totalScreens': totalScreens,
|
||||
'totalFeatures': totalFeatures,
|
||||
'totalTestCases': totalTestCases,
|
||||
'passedTestCases': passedTestCases,
|
||||
'failedTestCases': failedTestCases,
|
||||
'skippedTestCases': skippedTestCases,
|
||||
'totalDuration': totalDuration.inMilliseconds,
|
||||
'overallSuccessRate': overallSuccessRate,
|
||||
'startTime': startTime.toIso8601String(),
|
||||
'endTime': endTime.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
/// 에러 분석
|
||||
class ErrorAnalysis {
|
||||
final String errorId;
|
||||
final ErrorType errorType;
|
||||
final String description;
|
||||
final int occurrenceCount;
|
||||
final List<String> affectedScreens;
|
||||
final List<String> affectedFeatures;
|
||||
final RootCause? rootCause;
|
||||
final List<FixSuggestion> suggestedFixes;
|
||||
final bool wasAutoFixed;
|
||||
final Map<String, dynamic> context;
|
||||
|
||||
ErrorAnalysis({
|
||||
required this.errorId,
|
||||
required this.errorType,
|
||||
required this.description,
|
||||
required this.occurrenceCount,
|
||||
required this.affectedScreens,
|
||||
required this.affectedFeatures,
|
||||
this.rootCause,
|
||||
required this.suggestedFixes,
|
||||
required this.wasAutoFixed,
|
||||
required this.context,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'errorId': errorId,
|
||||
'errorType': errorType.toString(),
|
||||
'description': description,
|
||||
'occurrenceCount': occurrenceCount,
|
||||
'affectedScreens': affectedScreens,
|
||||
'affectedFeatures': affectedFeatures,
|
||||
'rootCause': rootCause?.toJson(),
|
||||
'suggestedFixes': suggestedFixes.map((f) => f.toJson()).toList(),
|
||||
'wasAutoFixed': wasAutoFixed,
|
||||
'context': context,
|
||||
};
|
||||
}
|
||||
|
||||
/// 성능 메트릭
|
||||
class PerformanceMetric {
|
||||
final String metricName;
|
||||
final MetricType type;
|
||||
final num value;
|
||||
final String unit;
|
||||
final num? baseline;
|
||||
final num? threshold;
|
||||
final bool isWithinThreshold;
|
||||
final Map<String, dynamic>? breakdown;
|
||||
|
||||
PerformanceMetric({
|
||||
required this.metricName,
|
||||
required this.type,
|
||||
required this.value,
|
||||
required this.unit,
|
||||
this.baseline,
|
||||
this.threshold,
|
||||
required this.isWithinThreshold,
|
||||
this.breakdown,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'metricName': metricName,
|
||||
'type': type.toString(),
|
||||
'value': value,
|
||||
'unit': unit,
|
||||
'baseline': baseline,
|
||||
'threshold': threshold,
|
||||
'isWithinThreshold': isWithinThreshold,
|
||||
'breakdown': breakdown,
|
||||
};
|
||||
}
|
||||
|
||||
/// 메트릭 타입
|
||||
enum MetricType {
|
||||
duration,
|
||||
memory,
|
||||
apiCalls,
|
||||
errorRate,
|
||||
throughput,
|
||||
custom,
|
||||
}
|
||||
|
||||
/// 리포트 설정
|
||||
class ReportConfiguration {
|
||||
final bool includeSuccessDetails;
|
||||
final bool includeErrorDetails;
|
||||
final bool includePerformanceMetrics;
|
||||
final bool includeScreenshots;
|
||||
final bool generateHtml;
|
||||
final bool generateJson;
|
||||
final bool generatePdf;
|
||||
final String outputDirectory;
|
||||
final Map<String, dynamic> customSettings;
|
||||
|
||||
ReportConfiguration({
|
||||
this.includeSuccessDetails = true,
|
||||
this.includeErrorDetails = true,
|
||||
this.includePerformanceMetrics = true,
|
||||
this.includeScreenshots = false,
|
||||
this.generateHtml = true,
|
||||
this.generateJson = true,
|
||||
this.generatePdf = false,
|
||||
required this.outputDirectory,
|
||||
this.customSettings = const {},
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'includeSuccessDetails': includeSuccessDetails,
|
||||
'includeErrorDetails': includeErrorDetails,
|
||||
'includePerformanceMetrics': includePerformanceMetrics,
|
||||
'includeScreenshots': includeScreenshots,
|
||||
'generateHtml': generateHtml,
|
||||
'generateJson': generateJson,
|
||||
'generatePdf': generatePdf,
|
||||
'outputDirectory': outputDirectory,
|
||||
'customSettings': customSettings,
|
||||
};
|
||||
}
|
||||
|
||||
/// 테스트 결과 (간단한 버전)
|
||||
class TestResult {
|
||||
final int totalTests;
|
||||
final int passedTests;
|
||||
final int failedTests;
|
||||
final int skippedTests;
|
||||
final List<TestFailure> failures;
|
||||
|
||||
TestResult({
|
||||
required this.totalTests,
|
||||
required this.passedTests,
|
||||
required this.failedTests,
|
||||
required this.skippedTests,
|
||||
required this.failures,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'totalTests': totalTests,
|
||||
'passedTests': passedTests,
|
||||
'failedTests': failedTests,
|
||||
'skippedTests': skippedTests,
|
||||
'failures': failures.map((f) => f.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
/// 테스트 실패
|
||||
class TestFailure {
|
||||
final String feature;
|
||||
final String message;
|
||||
final String? stackTrace;
|
||||
|
||||
TestFailure({
|
||||
required this.feature,
|
||||
required this.message,
|
||||
this.stackTrace,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'feature': feature,
|
||||
'message': message,
|
||||
'stackTrace': stackTrace,
|
||||
};
|
||||
}
|
||||
|
||||
/// 단계별 리포트
|
||||
class StepReport {
|
||||
final String stepName;
|
||||
final DateTime timestamp;
|
||||
final bool success;
|
||||
final String message;
|
||||
final Map<String, dynamic> details;
|
||||
|
||||
StepReport({
|
||||
required this.stepName,
|
||||
required this.timestamp,
|
||||
required this.success,
|
||||
required this.message,
|
||||
required this.details,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'stepName': stepName,
|
||||
'timestamp': timestamp.toIso8601String(),
|
||||
'success': success,
|
||||
'message': message,
|
||||
'details': details,
|
||||
};
|
||||
}
|
||||
|
||||
/// 에러 리포트
|
||||
class ErrorReport {
|
||||
final String errorType;
|
||||
final String message;
|
||||
final String? stackTrace;
|
||||
final DateTime timestamp;
|
||||
final Map<String, dynamic> context;
|
||||
|
||||
ErrorReport({
|
||||
required this.errorType,
|
||||
required this.message,
|
||||
this.stackTrace,
|
||||
required this.timestamp,
|
||||
required this.context,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'errorType': errorType,
|
||||
'message': message,
|
||||
'stackTrace': stackTrace,
|
||||
'timestamp': timestamp.toIso8601String(),
|
||||
'context': context,
|
||||
};
|
||||
}
|
||||
|
||||
/// 자동 수정 리포트
|
||||
class AutoFixReport {
|
||||
final String errorType;
|
||||
final String cause;
|
||||
final String solution;
|
||||
final bool success;
|
||||
final Map<String, dynamic> beforeData;
|
||||
final Map<String, dynamic> afterData;
|
||||
|
||||
AutoFixReport({
|
||||
required this.errorType,
|
||||
required this.cause,
|
||||
required this.solution,
|
||||
required this.success,
|
||||
required this.beforeData,
|
||||
required this.afterData,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'errorType': errorType,
|
||||
'cause': cause,
|
||||
'solution': solution,
|
||||
'success': success,
|
||||
'beforeData': beforeData,
|
||||
'afterData': afterData,
|
||||
};
|
||||
}
|
||||
|
||||
/// API 호출 리포트
|
||||
class ApiCallReport {
|
||||
final String endpoint;
|
||||
final String method;
|
||||
final int statusCode;
|
||||
final Duration duration;
|
||||
final Map<String, dynamic>? request;
|
||||
final Map<String, dynamic>? response;
|
||||
final bool success;
|
||||
|
||||
ApiCallReport({
|
||||
required this.endpoint,
|
||||
required this.method,
|
||||
required this.statusCode,
|
||||
required this.duration,
|
||||
this.request,
|
||||
this.response,
|
||||
required this.success,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'endpoint': endpoint,
|
||||
'method': method,
|
||||
'statusCode': statusCode,
|
||||
'duration': duration.inMilliseconds,
|
||||
'request': request,
|
||||
'response': response,
|
||||
'success': success,
|
||||
};
|
||||
}
|
||||
|
||||
/// 간단한 테스트 리포트 (BasicTestReport으로 이름 변경)
|
||||
class BasicTestReport {
|
||||
final String reportId;
|
||||
final String testName;
|
||||
final DateTime startTime;
|
||||
final DateTime endTime;
|
||||
final Duration duration;
|
||||
final Map<String, dynamic> environment;
|
||||
final TestResult testResult;
|
||||
final List<StepReport> steps;
|
||||
final List<ErrorReport> errors;
|
||||
final List<AutoFixReport> autoFixes;
|
||||
final Map<String, FeatureReport> features;
|
||||
final Map<String, List<ApiCallReport>> apiCalls;
|
||||
final String summary;
|
||||
|
||||
BasicTestReport({
|
||||
required this.reportId,
|
||||
required this.testName,
|
||||
required this.startTime,
|
||||
required this.endTime,
|
||||
required this.duration,
|
||||
required this.environment,
|
||||
required this.testResult,
|
||||
required this.steps,
|
||||
required this.errors,
|
||||
required this.autoFixes,
|
||||
required this.features,
|
||||
required this.apiCalls,
|
||||
required this.summary,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'reportId': reportId,
|
||||
'testName': testName,
|
||||
'startTime': startTime.toIso8601String(),
|
||||
'endTime': endTime.toIso8601String(),
|
||||
'duration': duration.inMilliseconds,
|
||||
'environment': environment,
|
||||
'testResult': testResult.toJson(),
|
||||
'steps': steps.map((s) => s.toJson()).toList(),
|
||||
'errors': errors.map((e) => e.toJson()).toList(),
|
||||
'autoFixes': autoFixes.map((f) => f.toJson()).toList(),
|
||||
'features': features.map((k, v) => MapEntry(k, v.toJson())),
|
||||
'apiCalls': apiCalls.map((k, v) => MapEntry(k, v.map((c) => c.toJson()).toList())),
|
||||
'summary': summary,
|
||||
};
|
||||
}
|
||||
424
test/integration/automated/framework/models/test_models.dart
Normal file
424
test/integration/automated/framework/models/test_models.dart
Normal file
@@ -0,0 +1,424 @@
|
||||
/// 화면 메타데이터
|
||||
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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user