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:
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