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:
500
doc/03_architecture/automated_test_class_diagram.md
Normal file
500
doc/03_architecture/automated_test_class_diagram.md
Normal file
@@ -0,0 +1,500 @@
|
||||
# Real API 자동화 테스트 프레임워크 - 클래스 다이어그램
|
||||
|
||||
## 1. 클래스 다이어그램
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
%% Core Framework
|
||||
class ScreenTestFramework {
|
||||
<<abstract>>
|
||||
#TestContext testContext
|
||||
#ApiErrorDiagnostics errorDiagnostics
|
||||
#AutoFixer autoFixer
|
||||
#TestDataGenerator dataGenerator
|
||||
#ReportCollector reportCollector
|
||||
+detectFeatures(ScreenMetadata) Future~List~TestableFeature~~
|
||||
+executeTests(List~TestableFeature~) Future~TestResult~
|
||||
+handleError(TestError) Future~void~
|
||||
+generateReport() Future~TestReport~
|
||||
#detectCustomFeatures(ScreenMetadata)* Future~List~TestableFeature~~
|
||||
#performCRUD()* Future~void~
|
||||
}
|
||||
|
||||
class ApiErrorDiagnostics {
|
||||
<<abstract>>
|
||||
-DiagnosticsManager diagnosticsManager
|
||||
-Map~String,ErrorPattern~ learnedPatterns
|
||||
+diagnose(ApiError) Future~ErrorDiagnosis~
|
||||
+analyzeRootCause(ErrorDiagnosis) Future~RootCause~
|
||||
+suggestFixes(RootCause) Future~List~FixSuggestion~~
|
||||
+learnFromError(ApiError, FixResult) Future~void~
|
||||
}
|
||||
|
||||
class AutoFixer {
|
||||
<<abstract>>
|
||||
-TestContext testContext
|
||||
-RetryHandler retryHandler
|
||||
-List~FixHistory~ fixHistory
|
||||
+attemptFix(FixSuggestion) Future~FixResult~
|
||||
+validateFix(FixResult) Future~bool~
|
||||
+rollback(FixResult) Future~void~
|
||||
+recordFix(FixResult) Future~void~
|
||||
#performCustomValidation(FixResult)* Future~bool~
|
||||
}
|
||||
|
||||
class TestDataGenerator {
|
||||
<<abstract>>
|
||||
-ValidationManager validationManager
|
||||
-Map~Type,GenerationStrategy~ strategies
|
||||
-Map~String,TestData~ generatedData
|
||||
+determineStrategy(DataRequirement) Future~GenerationStrategy~
|
||||
+generate(GenerationStrategy) Future~TestData~
|
||||
+validate(TestData) Future~bool~
|
||||
+generateRelated(DataRelationship) Future~Map~String,TestData~~
|
||||
}
|
||||
|
||||
%% Infrastructure
|
||||
class TestContext {
|
||||
-Map~String,dynamic~ data
|
||||
-Map~String,List~String~~ createdResources
|
||||
-Map~String,dynamic~ config
|
||||
-String currentScreen
|
||||
+getData(String) dynamic
|
||||
+setData(String, dynamic) void
|
||||
+addCreatedResourceId(String, String) void
|
||||
+getCreatedResourceIds() Map~String,List~String~~
|
||||
+recordFix(FixResult) void
|
||||
}
|
||||
|
||||
class ReportCollector {
|
||||
-List~TestResult~ results
|
||||
-ReportConfiguration config
|
||||
+collect(TestResult) Future~void~
|
||||
+generateReport() Future~TestReport~
|
||||
+exportHtml(TestReport) Future~String~
|
||||
+exportJson(TestReport) Future~String~
|
||||
}
|
||||
|
||||
%% Support
|
||||
class DiagnosticsManager {
|
||||
+checkTokenStatus() Future~Map~String,dynamic~~
|
||||
+checkPermissions() Future~Map~String,dynamic~~
|
||||
+validateSchema(Map~String,dynamic~) Future~Map~String,dynamic~~
|
||||
+checkConnectivity() Future~Map~String,dynamic~~
|
||||
+checkServerHealth() Future~Map~String,dynamic~~
|
||||
+savePattern(ErrorPattern) Future~void~
|
||||
}
|
||||
|
||||
class RetryHandler {
|
||||
-int maxAttempts
|
||||
-Duration backoffDelay
|
||||
+retry~T~(Function, {maxAttempts, backoffDelay}) Future~T~
|
||||
-calculateDelay(int) Duration
|
||||
}
|
||||
|
||||
class ValidationManager {
|
||||
-Map~Type,Schema~ schemas
|
||||
+validate(Map~String,dynamic~, Type) Future~bool~
|
||||
+validateField(String, dynamic, FieldConstraint) bool
|
||||
+getValidationErrors(Map~String,dynamic~, Type) List~String~
|
||||
}
|
||||
|
||||
%% Screen Tests
|
||||
class BaseScreenTest {
|
||||
<<abstract>>
|
||||
#ApiClient apiClient
|
||||
#GetIt getIt
|
||||
+getScreenMetadata()* ScreenMetadata
|
||||
+initializeServices()* Future~void~
|
||||
+setupTestEnvironment() Future~void~
|
||||
+teardownTestEnvironment() Future~void~
|
||||
+runTests() Future~TestResult~
|
||||
#getService()* dynamic
|
||||
#getResourceType()* String
|
||||
#getDefaultFilters()* Map~String,dynamic~
|
||||
}
|
||||
|
||||
class LicenseScreenTest {
|
||||
-LicenseService licenseService
|
||||
+getScreenMetadata() ScreenMetadata
|
||||
+initializeServices() Future~void~
|
||||
+detectCustomFeatures(ScreenMetadata) Future~List~TestableFeature~~
|
||||
+performExpiryCheck(TestData) Future~void~
|
||||
+performLicenseRenewal(TestData) Future~void~
|
||||
+performBulkImport(TestData) Future~void~
|
||||
}
|
||||
|
||||
class EquipmentScreenTest {
|
||||
-EquipmentService equipmentService
|
||||
+getScreenMetadata() ScreenMetadata
|
||||
+initializeServices() Future~void~
|
||||
+detectCustomFeatures(ScreenMetadata) Future~List~TestableFeature~~
|
||||
+performStatusTransition(TestData) Future~void~
|
||||
+performBulkTransfer(TestData) Future~void~
|
||||
}
|
||||
|
||||
class WarehouseScreenTest {
|
||||
-WarehouseService warehouseService
|
||||
+getScreenMetadata() ScreenMetadata
|
||||
+initializeServices() Future~void~
|
||||
+detectCustomFeatures(ScreenMetadata) Future~List~TestableFeature~~
|
||||
+performCapacityCheck(TestData) Future~void~
|
||||
+performInventoryReport(TestData) Future~void~
|
||||
}
|
||||
|
||||
%% Models
|
||||
class TestableFeature {
|
||||
+String featureName
|
||||
+FeatureType type
|
||||
+List~TestCase~ testCases
|
||||
+Map~String,dynamic~ metadata
|
||||
}
|
||||
|
||||
class TestCase {
|
||||
+String name
|
||||
+Function execute
|
||||
+Function verify
|
||||
+Function setup
|
||||
+Function teardown
|
||||
}
|
||||
|
||||
class TestResult {
|
||||
+String screenName
|
||||
+DateTime startTime
|
||||
+DateTime endTime
|
||||
+List~FeatureTestResult~ featureResults
|
||||
+List~TestError~ errors
|
||||
+calculateMetrics() void
|
||||
}
|
||||
|
||||
class ErrorDiagnosis {
|
||||
+ErrorType type
|
||||
+String description
|
||||
+Map~String,dynamic~ context
|
||||
+double confidence
|
||||
+List~String~ affectedEndpoints
|
||||
}
|
||||
|
||||
class FixSuggestion {
|
||||
+String fixId
|
||||
+FixType type
|
||||
+String description
|
||||
+List~FixAction~ actions
|
||||
+double successProbability
|
||||
}
|
||||
|
||||
%% Relationships
|
||||
ScreenTestFramework o-- TestContext
|
||||
ScreenTestFramework o-- ApiErrorDiagnostics
|
||||
ScreenTestFramework o-- AutoFixer
|
||||
ScreenTestFramework o-- TestDataGenerator
|
||||
ScreenTestFramework o-- ReportCollector
|
||||
|
||||
BaseScreenTest --|> ScreenTestFramework
|
||||
LicenseScreenTest --|> BaseScreenTest
|
||||
EquipmentScreenTest --|> BaseScreenTest
|
||||
WarehouseScreenTest --|> BaseScreenTest
|
||||
|
||||
ApiErrorDiagnostics o-- DiagnosticsManager
|
||||
AutoFixer o-- RetryHandler
|
||||
TestDataGenerator o-- ValidationManager
|
||||
|
||||
ScreenTestFramework ..> TestableFeature : creates
|
||||
TestableFeature o-- TestCase
|
||||
ScreenTestFramework ..> TestResult : produces
|
||||
ApiErrorDiagnostics ..> ErrorDiagnosis : produces
|
||||
ApiErrorDiagnostics ..> FixSuggestion : suggests
|
||||
```
|
||||
|
||||
## 2. 패키지 구조
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "framework"
|
||||
subgraph "core"
|
||||
STF[ScreenTestFramework]
|
||||
AED[ApiErrorDiagnostics]
|
||||
AF[AutoFixer]
|
||||
TDG[TestDataGenerator]
|
||||
end
|
||||
|
||||
subgraph "infrastructure"
|
||||
TC[TestContext]
|
||||
DC[DependencyContainer]
|
||||
RC[ReportCollector]
|
||||
end
|
||||
|
||||
subgraph "support"
|
||||
RH[RetryHandler]
|
||||
VM[ValidationManager]
|
||||
DM[DiagnosticsManager]
|
||||
end
|
||||
|
||||
subgraph "models"
|
||||
TM[test_models.dart]
|
||||
EM[error_models.dart]
|
||||
RM[report_models.dart]
|
||||
end
|
||||
end
|
||||
|
||||
subgraph "screens"
|
||||
subgraph "base"
|
||||
BST[BaseScreenTest]
|
||||
end
|
||||
|
||||
subgraph "license"
|
||||
LST[LicenseScreenTest]
|
||||
LTS[LicenseTestScenarios]
|
||||
end
|
||||
|
||||
subgraph "equipment"
|
||||
EST[EquipmentScreenTest]
|
||||
ETS[EquipmentTestScenarios]
|
||||
end
|
||||
|
||||
subgraph "warehouse"
|
||||
WST[WarehouseScreenTest]
|
||||
WTS[WarehouseTestScenarios]
|
||||
end
|
||||
end
|
||||
|
||||
subgraph "reports"
|
||||
subgraph "generators"
|
||||
HRG[HtmlReportGenerator]
|
||||
JRG[JsonReportGenerator]
|
||||
end
|
||||
|
||||
subgraph "templates"
|
||||
RT[ReportTemplate]
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## 3. 주요 디자인 패턴
|
||||
|
||||
### 3.1 Template Method Pattern
|
||||
```dart
|
||||
abstract class ScreenTestFramework {
|
||||
// 템플릿 메서드
|
||||
Future<TestResult> executeTests(List<TestableFeature> features) async {
|
||||
// 1. 준비
|
||||
await setupTestEnvironment();
|
||||
|
||||
// 2. 실행
|
||||
for (final feature in features) {
|
||||
await executeFeatureTests(feature);
|
||||
}
|
||||
|
||||
// 3. 정리
|
||||
await teardownTestEnvironment();
|
||||
|
||||
return generateReport();
|
||||
}
|
||||
|
||||
// 하위 클래스에서 구현
|
||||
Future<void> setupTestEnvironment();
|
||||
Future<void> teardownTestEnvironment();
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 Strategy Pattern
|
||||
```dart
|
||||
// 전략 인터페이스
|
||||
abstract class DiagnosticRule {
|
||||
bool canHandle(ApiError error);
|
||||
Future<ErrorDiagnosis> diagnose(ApiError error);
|
||||
}
|
||||
|
||||
// 구체적인 전략들
|
||||
class AuthenticationDiagnosticRule implements DiagnosticRule {
|
||||
@override
|
||||
bool canHandle(ApiError error) => error.type == ErrorType.authentication;
|
||||
|
||||
@override
|
||||
Future<ErrorDiagnosis> diagnose(ApiError error) async {
|
||||
// 인증 관련 진단 로직
|
||||
}
|
||||
}
|
||||
|
||||
class NetworkDiagnosticRule implements DiagnosticRule {
|
||||
@override
|
||||
bool canHandle(ApiError error) => error.type == ErrorType.network;
|
||||
|
||||
@override
|
||||
Future<ErrorDiagnosis> diagnose(ApiError error) async {
|
||||
// 네트워크 관련 진단 로직
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 Builder Pattern
|
||||
```dart
|
||||
class TestReportBuilder {
|
||||
TestReport _report;
|
||||
|
||||
TestReportBuilder withSummary(TestSummary summary) {
|
||||
_report.summary = summary;
|
||||
return this;
|
||||
}
|
||||
|
||||
TestReportBuilder withScreenReports(List<ScreenTestReport> reports) {
|
||||
_report.screenReports = reports;
|
||||
return this;
|
||||
}
|
||||
|
||||
TestReportBuilder withErrorAnalyses(List<ErrorAnalysis> analyses) {
|
||||
_report.errorAnalyses = analyses;
|
||||
return this;
|
||||
}
|
||||
|
||||
TestReport build() => _report;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 Observer Pattern
|
||||
```dart
|
||||
abstract class TestEventListener {
|
||||
void onTestStarted(TestCase testCase);
|
||||
void onTestCompleted(TestCaseResult result);
|
||||
void onTestFailed(TestError error);
|
||||
}
|
||||
|
||||
class TestEventNotifier {
|
||||
final List<TestEventListener> _listeners = [];
|
||||
|
||||
void addListener(TestEventListener listener) {
|
||||
_listeners.add(listener);
|
||||
}
|
||||
|
||||
void notifyTestStarted(TestCase testCase) {
|
||||
for (final listener in _listeners) {
|
||||
listener.onTestStarted(testCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 확장 포인트
|
||||
|
||||
### 4.1 새로운 화면 추가
|
||||
```dart
|
||||
class NewScreenTest extends BaseScreenTest {
|
||||
@override
|
||||
ScreenMetadata getScreenMetadata() {
|
||||
// 화면 메타데이터 정의
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<TestableFeature>> detectCustomFeatures(ScreenMetadata metadata) async {
|
||||
// 화면별 커스텀 기능 정의
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 새로운 진단 룰 추가
|
||||
```dart
|
||||
class CustomDiagnosticRule implements DiagnosticRule {
|
||||
@override
|
||||
bool canHandle(ApiError error) {
|
||||
// 처리 가능 여부 판단
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ErrorDiagnosis> diagnose(ApiError error) async {
|
||||
// 진단 로직 구현
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 새로운 수정 전략 추가
|
||||
```dart
|
||||
class CustomFixStrategy implements FixStrategy {
|
||||
@override
|
||||
Future<FixResult> apply(FixContext context) async {
|
||||
// 수정 로직 구현
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 사용 예제
|
||||
|
||||
```dart
|
||||
// 테스트 실행
|
||||
void main() async {
|
||||
// 의존성 설정
|
||||
final testContext = TestContext();
|
||||
final errorDiagnostics = ConcreteApiErrorDiagnostics(
|
||||
diagnosticsManager: DiagnosticsManager(),
|
||||
);
|
||||
final autoFixer = ConcreteAutoFixer(
|
||||
testContext: testContext,
|
||||
retryHandler: RetryHandler(),
|
||||
);
|
||||
final dataGenerator = ConcreteTestDataGenerator(
|
||||
validationManager: ValidationManager(),
|
||||
);
|
||||
final reportCollector = ReportCollector(
|
||||
config: ReportConfiguration(
|
||||
outputDirectory: 'test/reports',
|
||||
),
|
||||
);
|
||||
|
||||
// 라이선스 화면 테스트
|
||||
final licenseTest = LicenseScreenTest(
|
||||
apiClient: ApiClient(),
|
||||
getIt: GetIt.instance,
|
||||
testContext: testContext,
|
||||
errorDiagnostics: errorDiagnostics,
|
||||
autoFixer: autoFixer,
|
||||
dataGenerator: dataGenerator,
|
||||
reportCollector: reportCollector,
|
||||
);
|
||||
|
||||
// 테스트 실행
|
||||
final result = await licenseTest.runTests();
|
||||
|
||||
// 리포트 생성
|
||||
final report = await reportCollector.generateReport();
|
||||
print('테스트 완료: ${report.summary.overallSuccessRate}% 성공');
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 성능 최적화 전략
|
||||
|
||||
### 6.1 병렬 실행
|
||||
- 독립적인 테스트 케이스는 병렬로 실행
|
||||
- 화면별 테스트는 격리된 환경에서 동시 실행
|
||||
|
||||
### 6.2 리소스 재사용
|
||||
- API 클라이언트 연결 풀링
|
||||
- 테스트 데이터 캐싱
|
||||
- 인증 토큰 재사용
|
||||
|
||||
### 6.3 스마트 재시도
|
||||
- 지수 백오프 알고리즘
|
||||
- 에러 타입별 재시도 전략
|
||||
- 학습된 패턴 기반 빠른 수정
|
||||
|
||||
## 7. 모니터링 및 분석
|
||||
|
||||
### 7.1 실시간 모니터링
|
||||
- 테스트 진행 상황 대시보드
|
||||
- 에러 발생 즉시 알림
|
||||
- 성능 메트릭 실시간 추적
|
||||
|
||||
### 7.2 사후 분석
|
||||
- 테스트 결과 트렌드 분석
|
||||
- 에러 패턴 식별
|
||||
- 성능 병목 지점 발견
|
||||
|
||||
## 8. 결론
|
||||
|
||||
이 아키텍처는 다음과 같은 장점을 제공합니다:
|
||||
|
||||
1. **확장성**: 새로운 화면과 기능을 쉽게 추가
|
||||
2. **유지보수성**: 명확한 책임 분리와 모듈화
|
||||
3. **안정성**: 자동 에러 진단 및 수정
|
||||
4. **효율성**: 병렬 실행과 리소스 최적화
|
||||
5. **가시성**: 상세한 리포트와 모니터링
|
||||
|
||||
SOLID 원칙을 준수하며, 실제 프로덕션 환경에서 안정적으로 운영될 수 있는 구조입니다.
|
||||
469
doc/03_architecture/automated_test_framework_architecture.md
Normal file
469
doc/03_architecture/automated_test_framework_architecture.md
Normal file
@@ -0,0 +1,469 @@
|
||||
# Real API 기반 자동화 테스트 프레임워크 아키텍처
|
||||
|
||||
## 1. 개요
|
||||
|
||||
Real API 기반 자동화 테스트 프레임워크는 실제 API와 통신하며 화면별 기능을 자동으로 감지하고 테스트하는 고급 테스트 시스템입니다. 이 프레임워크는 API 에러 진단, 자동 수정, 테스트 데이터 생성 등의 기능을 포함합니다.
|
||||
|
||||
## 2. 아키텍처 개요
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Test Runner Layer"
|
||||
TR[Test Runner]
|
||||
TO[Test Orchestrator]
|
||||
end
|
||||
|
||||
subgraph "Framework Core"
|
||||
STF[ScreenTestFramework]
|
||||
AED[ApiErrorDiagnostics]
|
||||
AF[AutoFixer]
|
||||
TDG[TestDataGenerator]
|
||||
end
|
||||
|
||||
subgraph "Infrastructure Layer"
|
||||
TC[TestContext]
|
||||
DC[DependencyContainer]
|
||||
RC[ReportCollector]
|
||||
end
|
||||
|
||||
subgraph "Screen Test Layer"
|
||||
BST[BaseScreenTest]
|
||||
LST[LicenseScreenTest]
|
||||
EST[EquipmentScreenTest]
|
||||
WST[WarehouseScreenTest]
|
||||
end
|
||||
|
||||
subgraph "Support Layer"
|
||||
RH[RetryHandler]
|
||||
VM[ValidationManager]
|
||||
DM[DiagnosticsManager]
|
||||
end
|
||||
|
||||
TR --> TO
|
||||
TO --> STF
|
||||
STF --> BST
|
||||
BST --> LST
|
||||
BST --> EST
|
||||
BST --> WST
|
||||
|
||||
STF --> AED
|
||||
STF --> AF
|
||||
STF --> TDG
|
||||
|
||||
AED --> DM
|
||||
AF --> RH
|
||||
TDG --> VM
|
||||
|
||||
STF --> TC
|
||||
TC --> DC
|
||||
STF --> RC
|
||||
```
|
||||
|
||||
## 3. 핵심 컴포넌트 설계
|
||||
|
||||
### 3.1 ScreenTestFramework
|
||||
|
||||
```dart
|
||||
abstract class ScreenTestFramework {
|
||||
// 화면 기능 자동 감지
|
||||
Future<List<TestableFeature>> detectFeatures(ScreenMetadata metadata);
|
||||
|
||||
// 테스트 실행
|
||||
Future<TestResult> executeTests(List<TestableFeature> features);
|
||||
|
||||
// 에러 처리
|
||||
Future<void> handleError(TestError error);
|
||||
|
||||
// 리포트 생성
|
||||
Future<TestReport> generateReport();
|
||||
}
|
||||
|
||||
class ScreenMetadata {
|
||||
final String screenName;
|
||||
final Type controllerType;
|
||||
final List<ApiEndpoint> relatedEndpoints;
|
||||
final Map<String, dynamic> screenCapabilities;
|
||||
}
|
||||
|
||||
class TestableFeature {
|
||||
final String featureName;
|
||||
final FeatureType type;
|
||||
final List<TestCase> testCases;
|
||||
final Map<String, dynamic> metadata;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 ApiErrorDiagnostics
|
||||
|
||||
```dart
|
||||
abstract class ApiErrorDiagnostics {
|
||||
// 에러 분석
|
||||
Future<ErrorDiagnosis> diagnose(ApiError error);
|
||||
|
||||
// 근본 원인 분석
|
||||
Future<RootCause> analyzeRootCause(ErrorDiagnosis diagnosis);
|
||||
|
||||
// 수정 제안
|
||||
Future<List<FixSuggestion>> suggestFixes(RootCause rootCause);
|
||||
|
||||
// 패턴 학습
|
||||
Future<void> learnFromError(ApiError error, FixResult result);
|
||||
}
|
||||
|
||||
class ErrorDiagnosis {
|
||||
final ErrorType type;
|
||||
final String description;
|
||||
final Map<String, dynamic> context;
|
||||
final double confidence;
|
||||
final List<String> affectedEndpoints;
|
||||
}
|
||||
|
||||
class RootCause {
|
||||
final String cause;
|
||||
final CauseCategory category;
|
||||
final List<Evidence> evidence;
|
||||
final Map<String, dynamic> details;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 AutoFixer
|
||||
|
||||
```dart
|
||||
abstract class AutoFixer {
|
||||
// 자동 수정 시도
|
||||
Future<FixResult> attemptFix(FixSuggestion suggestion);
|
||||
|
||||
// 수정 검증
|
||||
Future<bool> validateFix(FixResult result);
|
||||
|
||||
// 롤백
|
||||
Future<void> rollback(FixResult result);
|
||||
|
||||
// 수정 이력 관리
|
||||
Future<void> recordFix(FixResult result);
|
||||
}
|
||||
|
||||
class FixSuggestion {
|
||||
final String fixId;
|
||||
final FixType type;
|
||||
final String description;
|
||||
final List<FixAction> actions;
|
||||
final double successProbability;
|
||||
}
|
||||
|
||||
class FixResult {
|
||||
final bool success;
|
||||
final String fixId;
|
||||
final List<Change> changes;
|
||||
final Duration duration;
|
||||
final Map<String, dynamic> metrics;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 TestDataGenerator
|
||||
|
||||
```dart
|
||||
abstract class TestDataGenerator {
|
||||
// 데이터 생성 전략
|
||||
Future<GenerationStrategy> determineStrategy(DataRequirement requirement);
|
||||
|
||||
// 데이터 생성
|
||||
Future<TestData> generate(GenerationStrategy strategy);
|
||||
|
||||
// 데이터 검증
|
||||
Future<bool> validate(TestData data);
|
||||
|
||||
// 관계 데이터 생성
|
||||
Future<Map<String, TestData>> generateRelated(DataRelationship relationship);
|
||||
}
|
||||
|
||||
class DataRequirement {
|
||||
final Type dataType;
|
||||
final Map<String, FieldConstraint> constraints;
|
||||
final List<DataRelationship> relationships;
|
||||
final int quantity;
|
||||
}
|
||||
|
||||
class TestData {
|
||||
final String id;
|
||||
final Type type;
|
||||
final Map<String, dynamic> data;
|
||||
final DateTime createdAt;
|
||||
final List<String> relatedIds;
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 상호작용 패턴
|
||||
|
||||
### 4.1 테스트 실행 시퀀스
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant TR as Test Runner
|
||||
participant STF as ScreenTestFramework
|
||||
participant TDG as TestDataGenerator
|
||||
participant BST as BaseScreenTest
|
||||
participant AED as ApiErrorDiagnostics
|
||||
participant AF as AutoFixer
|
||||
participant RC as ReportCollector
|
||||
|
||||
TR->>STF: initializeTest(screenName)
|
||||
STF->>STF: detectFeatures()
|
||||
STF->>TDG: generateTestData()
|
||||
TDG-->>STF: testData
|
||||
|
||||
STF->>BST: executeScreenTest(features, data)
|
||||
BST->>BST: runTestCases()
|
||||
|
||||
alt Test Success
|
||||
BST-->>STF: TestResult(success)
|
||||
STF->>RC: collectResult()
|
||||
else Test Failure
|
||||
BST-->>STF: TestError
|
||||
STF->>AED: diagnose(error)
|
||||
AED-->>STF: ErrorDiagnosis
|
||||
STF->>AF: attemptFix(diagnosis)
|
||||
AF-->>STF: FixResult
|
||||
|
||||
alt Fix Success
|
||||
STF->>BST: retryTest()
|
||||
else Fix Failed
|
||||
STF->>RC: recordFailure()
|
||||
end
|
||||
end
|
||||
|
||||
STF->>RC: generateReport()
|
||||
RC-->>TR: TestReport
|
||||
```
|
||||
|
||||
### 4.2 에러 진단 및 자동 수정 플로우
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[API Error Detected] --> B{Error Type?}
|
||||
|
||||
B -->|Authentication| C[Auth Diagnostics]
|
||||
B -->|Data Validation| D[Validation Diagnostics]
|
||||
B -->|Network| E[Network Diagnostics]
|
||||
B -->|Server Error| F[Server Diagnostics]
|
||||
|
||||
C --> G[Analyze Token Status]
|
||||
D --> H[Check Data Format]
|
||||
E --> I[Test Connectivity]
|
||||
F --> J[Check Server Health]
|
||||
|
||||
G --> K{Token Valid?}
|
||||
K -->|No| L[Refresh Token]
|
||||
K -->|Yes| M[Check Permissions]
|
||||
|
||||
H --> N{Data Valid?}
|
||||
N -->|No| O[Generate Valid Data]
|
||||
N -->|Yes| P[Check Constraints]
|
||||
|
||||
L --> Q[Retry Request]
|
||||
O --> Q
|
||||
M --> Q
|
||||
P --> Q
|
||||
|
||||
Q --> R{Success?}
|
||||
R -->|Yes| S[Continue Test]
|
||||
R -->|No| T[Record Failure]
|
||||
```
|
||||
|
||||
## 5. 디렉토리 구조
|
||||
|
||||
```
|
||||
test/integration/automated/
|
||||
├── framework/
|
||||
│ ├── core/
|
||||
│ │ ├── screen_test_framework.dart
|
||||
│ │ ├── api_error_diagnostics.dart
|
||||
│ │ ├── auto_fixer.dart
|
||||
│ │ └── test_data_generator.dart
|
||||
│ ├── infrastructure/
|
||||
│ │ ├── test_context.dart
|
||||
│ │ ├── dependency_container.dart
|
||||
│ │ └── report_collector.dart
|
||||
│ ├── support/
|
||||
│ │ ├── retry_handler.dart
|
||||
│ │ ├── validation_manager.dart
|
||||
│ │ └── diagnostics_manager.dart
|
||||
│ └── models/
|
||||
│ ├── test_models.dart
|
||||
│ ├── error_models.dart
|
||||
│ └── report_models.dart
|
||||
├── screens/
|
||||
│ ├── base/
|
||||
│ │ └── base_screen_test.dart
|
||||
│ ├── license/
|
||||
│ │ ├── license_screen_test.dart
|
||||
│ │ └── license_test_scenarios.dart
|
||||
│ ├── equipment/
|
||||
│ │ ├── equipment_screen_test.dart
|
||||
│ │ └── equipment_test_scenarios.dart
|
||||
│ └── warehouse/
|
||||
│ ├── warehouse_screen_test.dart
|
||||
│ └── warehouse_test_scenarios.dart
|
||||
└── reports/
|
||||
├── generators/
|
||||
│ ├── html_report_generator.dart
|
||||
│ └── json_report_generator.dart
|
||||
└── templates/
|
||||
└── report_template.html
|
||||
```
|
||||
|
||||
## 6. 확장 가능한 구조
|
||||
|
||||
### 6.1 플러그인 시스템
|
||||
|
||||
```dart
|
||||
abstract class TestPlugin {
|
||||
String get name;
|
||||
String get version;
|
||||
|
||||
Future<void> initialize(TestContext context);
|
||||
Future<void> beforeTest(TestCase testCase);
|
||||
Future<void> afterTest(TestResult result);
|
||||
Future<void> onError(TestError error);
|
||||
}
|
||||
|
||||
class PluginManager {
|
||||
final List<TestPlugin> _plugins = [];
|
||||
|
||||
void register(TestPlugin plugin) {
|
||||
_plugins.add(plugin);
|
||||
}
|
||||
|
||||
Future<void> executePlugins(PluginPhase phase, dynamic data) async {
|
||||
for (final plugin in _plugins) {
|
||||
await plugin.execute(phase, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 커스텀 진단 룰
|
||||
|
||||
```dart
|
||||
abstract class DiagnosticRule {
|
||||
String get ruleId;
|
||||
int get priority;
|
||||
|
||||
bool canHandle(ApiError error);
|
||||
Future<ErrorDiagnosis> diagnose(ApiError error);
|
||||
}
|
||||
|
||||
class DiagnosticRuleEngine {
|
||||
final List<DiagnosticRule> _rules = [];
|
||||
|
||||
void addRule(DiagnosticRule rule) {
|
||||
_rules.add(rule);
|
||||
_rules.sort((a, b) => b.priority.compareTo(a.priority));
|
||||
}
|
||||
|
||||
Future<ErrorDiagnosis> diagnose(ApiError error) async {
|
||||
for (final rule in _rules) {
|
||||
if (rule.canHandle(error)) {
|
||||
return await rule.diagnose(error);
|
||||
}
|
||||
}
|
||||
return DefaultDiagnosis(error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7. SOLID 원칙 적용
|
||||
|
||||
### 7.1 Single Responsibility Principle (SRP)
|
||||
- 각 클래스는 하나의 책임만 가짐
|
||||
- ScreenTestFramework: 화면 테스트 조정
|
||||
- ApiErrorDiagnostics: 에러 진단
|
||||
- AutoFixer: 에러 수정
|
||||
- TestDataGenerator: 데이터 생성
|
||||
|
||||
### 7.2 Open/Closed Principle (OCP)
|
||||
- 플러그인 시스템을 통한 확장
|
||||
- 추상 클래스를 통한 구현 확장
|
||||
- 새로운 화면 테스트 추가 시 기존 코드 수정 불필요
|
||||
|
||||
### 7.3 Liskov Substitution Principle (LSP)
|
||||
- 모든 화면 테스트는 BaseScreenTest를 대체 가능
|
||||
- 모든 진단 룰은 DiagnosticRule 인터페이스 준수
|
||||
|
||||
### 7.4 Interface Segregation Principle (ISP)
|
||||
- 작고 구체적인 인터페이스 제공
|
||||
- 클라이언트가 필요하지 않은 메서드에 의존하지 않음
|
||||
|
||||
### 7.5 Dependency Inversion Principle (DIP)
|
||||
- 추상화에 의존, 구체적인 구현에 의존하지 않음
|
||||
- DI 컨테이너를 통한 의존성 주입
|
||||
|
||||
## 8. 성능 및 확장성 고려사항
|
||||
|
||||
### 8.1 병렬 처리
|
||||
```dart
|
||||
class ParallelTestExecutor {
|
||||
Future<List<TestResult>> executeParallel(
|
||||
List<TestCase> testCases,
|
||||
{int maxConcurrency = 4}
|
||||
) async {
|
||||
final pool = Pool(maxConcurrency);
|
||||
final results = <TestResult>[];
|
||||
|
||||
await Future.wait(
|
||||
testCases.map((testCase) =>
|
||||
pool.withResource(() => executeTest(testCase))
|
||||
)
|
||||
);
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 캐싱 전략
|
||||
```dart
|
||||
class TestDataCache {
|
||||
final Duration _ttl = Duration(minutes: 30);
|
||||
final Map<String, CachedData> _cache = {};
|
||||
|
||||
Future<TestData> getOrGenerate(
|
||||
String key,
|
||||
Future<TestData> Function() generator
|
||||
) async {
|
||||
final cached = _cache[key];
|
||||
if (cached != null && !cached.isExpired) {
|
||||
return cached.data;
|
||||
}
|
||||
|
||||
final data = await generator();
|
||||
_cache[key] = CachedData(data, DateTime.now());
|
||||
return data;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 모니터링 및 로깅
|
||||
|
||||
```dart
|
||||
class TestMonitor {
|
||||
final MetricsCollector _metrics;
|
||||
final Logger _logger;
|
||||
|
||||
Future<void> monitorTest(TestCase testCase) async {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
try {
|
||||
await testCase.execute();
|
||||
_metrics.recordSuccess(testCase.name, stopwatch.elapsed);
|
||||
} catch (e) {
|
||||
_metrics.recordFailure(testCase.name, stopwatch.elapsed);
|
||||
_logger.error('Test failed: ${testCase.name}', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 10. 결론
|
||||
|
||||
이 아키텍처는 확장 가능하고 유지보수가 용이한 Real API 기반 자동화 테스트 프레임워크를 제공합니다. SOLID 원칙을 준수하며, 플러그인 시스템을 통해 쉽게 확장할 수 있고, 에러 진단 및 자동 수정 기능을 통해 테스트의 안정성을 높입니다.
|
||||
Reference in New Issue
Block a user