Files
superport/doc/03_architecture/automated_test_class_diagram.md
JiWoong Sul 198aac6525
Some checks failed
Flutter Test & Quality Check / Test on macos-latest (push) Has been cancelled
Flutter Test & Quality Check / Test on ubuntu-latest (push) Has been cancelled
Flutter Test & Quality Check / Build APK (push) Has been cancelled
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
2025-08-05 20:24:05 +09:00

13 KiB

Real API 자동화 테스트 프레임워크 - 클래스 다이어그램

1. 클래스 다이어그램

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. 패키지 구조

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

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

// 전략 인터페이스
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

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

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 새로운 화면 추가

class NewScreenTest extends BaseScreenTest {
  @override
  ScreenMetadata getScreenMetadata() {
    // 화면 메타데이터 정의
  }
  
  @override
  Future<List<TestableFeature>> detectCustomFeatures(ScreenMetadata metadata) async {
    // 화면별 커스텀 기능 정의
  }
}

4.2 새로운 진단 룰 추가

class CustomDiagnosticRule implements DiagnosticRule {
  @override
  bool canHandle(ApiError error) {
    // 처리 가능 여부 판단
  }
  
  @override
  Future<ErrorDiagnosis> diagnose(ApiError error) async {
    // 진단 로직 구현
  }
}

4.3 새로운 수정 전략 추가

class CustomFixStrategy implements FixStrategy {
  @override
  Future<FixResult> apply(FixContext context) async {
    // 수정 로직 구현
  }
}

5. 사용 예제

// 테스트 실행
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 원칙을 준수하며, 실제 프로덕션 환경에서 안정적으로 운영될 수 있는 구조입니다.