# recordingtest 사내 WPF 3D 편집 응용(자체 엔진 **HmEG**, MEF plugin 아키텍처)에 대한 **사용자 입력 회귀 테스트 자동화 도구**. 도구 자체이지 SUT가 아니다. 자세한 운영 지침은 [CLAUDE.md](CLAUDE.md), 현재 진행 상태는 [PROGRESS.md](PROGRESS.md), 다음 할 일은 [PLAN.md](PLAN.md)를 참고. ## 핵심 전략 — Golden-file 회귀 수동 테스트 입력을 레코딩 → 리플레이 → 결과 저장 파일을 정규화 후 baseline과 diff. ApprovalTests 패턴과 동형이며 SUT 코드 변경 협조를 최소화하기 위한 의도적 선택이다. ``` [수동 테스트] → 입력 레코드 + 결과 파일 A (approved baseline) [회귀 시점] → 입력 리플레이 → 결과 파일 B → normalize → diff(A, B) ``` ## 3계층 아키텍처 본 도구는 **EG-BIM Modeler 외 다양한 WPF 응용**을 대상으로 하고, 사용자 WPF 응용군 대다수가 자체 3D 엔진 **HmEG**를 공유한다. 따라서 코드는 엄격히 3계층으로 분리된다 (의존 방향 단방향, 자세한 규칙은 [CLAUDE.md §8.1](CLAUDE.md)): ``` App-specific (e.g. EgBim) ──→ HmEG-aware ──→ Generic (특정 앱만) (HmEG 호스팅 앱 공통) (임의 WPF 앱) ``` `Recordingtest.Architecture.Tests` 가 `Assembly.GetReferencedAssemblies()` 검사로 빌드 시점에 규칙을 강제한다. 새 SUT를 추가할 때는 App-specific 계층에 플러그인 진입점 + 어댑터만 작성하고 Generic + HmEG-aware 전부 재사용. ## 모듈 구성 ### Generic tier — 임의 WPF 응용 | 모듈 | 책임 | 상태 | |------|------|------| | [Recordingtest.Bridge.Abstractions](src/Recordingtest.Bridge.Abstractions/) | `IEngineStateProvider`/`CameraSnapshot`/`SceneSnapshot` 등 SUT-중립 인터페이스 | ✓ | | [Recordingtest.SutProber](src/Recordingtest.SutProber/) | SUT 정적 probe (plugin/Json/assembly 카탈로그) | PoC pass | | [Recordingtest.Recorder](src/Recordingtest.Recorder/) | 입력 캡처 (UIA element path + offset + 키/마우스/포커스) | PoC pass | | [Recordingtest.Player](src/Recordingtest.Player/) | 시나리오 재생, 비동기 동기화, null-target fallback | PoC pass | | [Recordingtest.Normalizer](src/Recordingtest.Normalizer/) | 결과 파일 정규화 (timestamp/GUID/path/float/order) | PoC pass | | [Recordingtest.DiffReporter](src/Recordingtest.DiffReporter/) | approved vs received diff 리포트 | PoC pass | | [Recordingtest.Runner](src/Recordingtest.Runner/) | 5-모듈 E2E 파이프라인 + 실패 triage | PoC pass | ### HmEG-aware tier — HmEG 호스팅 앱 공통 | 모듈 | 책임 | 상태 | |------|------|------| | [Recordingtest.Hmeg.Bridge](src/Hmeg/Recordingtest.Hmeg.Bridge/) | `HmegDirectStateProvider` — HmEG 공개 API(Space/HmEGViewport/ISelectable)로 상태 읽기. 앱에 람다로 진입점 주입 | v3 wired | | [Recordingtest.Hmeg.Catalog](src/Hmeg/Recordingtest.Hmeg.Catalog/) | HmEG 정적 분석 카탈로그 | PoC pass | | [Recordingtest.Hmeg.Bridge.Client](src/Hmeg/Recordingtest.Hmeg.Bridge.Client/) | `/scene` `/camera` `/selection` HTTP 클라이언트 | v2 pass | ### App-specific tier — 현재 SUT: EG-BIM Modeler | 모듈 | 책임 | 상태 | |------|------|------| | [Recordingtest.Sut.EgBim.PluginHost](src/Sut/EgBim/Recordingtest.Sut.EgBim.PluginHost/) | MEF 진입점(`EditorPlugin` 상속), `BridgeHttpServer` 부팅, `HmegDirectStateProvider` 람다에 `RootSpace`/`View`/`AppManager.FileManager.CurrentFile` 주입 | v3 wired | ## 작업 사이클 — Planner / Generator / Evaluator Anthropic harness design 원칙을 채택. 같은 에이전트가 생성과 평가를 겸하지 않는다. 1. `/contract ` — Sprint Contract 작성 (`docs/contracts/.md`, 검증 가능한 DoD) 2. Generator — 계약 기준으로 구현 3. `/evaluate ` — 독립 evaluator가 채점, pass 시에만 PROGRESS.md 갱신 ## 기술 스택 - **언어**: C# / .NET (SUT와 동일 생태계) - **UI 자동화**: [FlaUI](https://github.com/FlaUI/FlaUI) 1순위, Win32 low-level hook hybrid - **시나리오 포맷**: YAML/JSON (git diff 친화적) - **베이스라인**: `*.approved.{ext}` / `*.received.{ext}` ## 주요 이정표 - **2026-04-08 — 첫 E2E 성공** 🎉 Smoke 2회차에서 수동 테스트 시나리오 → 재생 → SUT에 Box geometry 생성 확인 (box-v5-clean.yaml). - **2026-04-08 — Raw 시나리오 E2E 성공** 🎉 수동 cleanup 없이 recorder 원본 `box-v6.yaml`이 그대로 재생되어 Box 생성 (이슈 #14). Player에 null-target fallback, SUT foreground 능동 대기, 선두 alt+tab 노이즈 자동 skip, 스텝 간 타이밍 보존 추가. - **2026-04-09 — 3-tier 분리 완료** — Generic / HmEG-aware / App-specific 물리적 분리, `Recordingtest.Architecture.Tests`가 의존 그래프 강제. 같은 날 engine-bridge v3 EgBim 람다 실 wire-up (코드 쪽 완료, 라이브 검증 대기). - **126 단위 테스트** green (Recorder/Player/Normalizer/DiffReporter/Runner/Hmeg.* /Sut.EgBim.* /Architecture) 자세한 과정은 [docs/history/](docs/history/), 결정 근거는 [docs/contracts/](docs/contracts/) + [docs/hmeg-api-survey.md](docs/hmeg-api-survey.md) 참고. ## Gap 현황 (주요) - **Gap A~H** (smoke 1~2회차) — 전부 fix (#11/#12/#13/#14) - **Gap I (recorder root-cause)** — EG-BIM Modeler의 CommandBox 등 핵심 입력 컨트롤이 AutomationPeer를 노출하지 않아 UIA 외부에서 본질적으로 식별 불가. **deferred**. 현재는 Player null-target fallback(Type→OS 포커스 / Click→raw_coord)이 공식 우회 전략. 근본 해소는 generic WPF DLL injection 또는 SUT-side AutomationPeer 부착 PoC가 선결. ## 디렉터리 ``` recordingtest/ ├── src/ │ ├── Recordingtest.Bridge.Abstractions/ # Generic — 인터페이스 │ ├── Recordingtest.Recorder/ # Generic │ ├── Recordingtest.Player/ # Generic │ ├── Recordingtest.Normalizer/ # Generic │ ├── Recordingtest.DiffReporter/ # Generic │ ├── Recordingtest.Runner/ # Generic │ ├── Recordingtest.SutProber/ # Generic │ ├── Hmeg/ │ │ ├── Recordingtest.Hmeg.Bridge/ # HmEG-aware │ │ ├── Recordingtest.Hmeg.Catalog/ # HmEG-aware │ │ ├── Recordingtest.Hmeg.Bridge.Client/ # HmEG-aware │ │ └── Recordingtest.Hmeg.Catalog.Probe/ # HmEG-aware CLI │ └── Sut/ │ └── EgBim/ │ └── Recordingtest.Sut.EgBim.PluginHost/ # App-specific ├── tests/ # 같은 계층 구조로 미러링 + Architecture.Tests ├── scenarios/ # 시나리오 YAML (box-v*.yaml) ├── docs/ │ ├── contracts/ # Sprint Contracts + evaluations │ ├── history/ # 작업 히스토리 │ ├── sut-catalog/ # sut-prober 산출물 │ ├── engine-catalog/ # HmEG 후보 카탈로그 (정적 분석) │ ├── hmeg-api-survey.md # HmEG public API 조사 메모 │ └── guides/ # smoke test, deploy 가이드 ├── CLAUDE.md # 에이전트 운영 지침 + §8.1 3-tier 규칙 ├── PROGRESS.md # 완료 상태 (세션 간 공유 메모리) └── PLAN.md # 우선순위 큐 ``` ## 저장소 - Origin: https://gitea.hmac.kr/kimminsung/recordingtest - 이슈/PR은 동일 Gitea, 커밋 메시지에 `#N` 참조