Framework Testing Guide

이 문서는 _Framework 의 테스트를 작성/실행하는 표준 방법을 설명한다. 작업 전 MCP_README.md -> MCP_Rules.md -> MCP_Index.md 순서로 먼저 확인할 것.

1. Assembly 구조

Assets/_Framework/Tests/
    Shared/                          Framework.Tests.Shared.asmdef (Any Platform)
        TestFramework/               공통 Fixture 기반 클래스
        Utilities/                   공통 Mock/Helper
    EditMode/                        Framework.Tests.EditMode.asmdef (Editor 전용)
        Runtime/Common/
        Runtime/Core/
        Runtime/Patterns/
        Runtime/Systems/
        Integration/
        Performance/
        Regression/
    PlayMode/                        Framework.Tests.PlayMode.asmdef (Any Platform)
        Runtime/Systems/              실시간 대기([UnityTest])가 필요한 테스트만
  • 실제 시간 경과(WaitForSeconds, 실시간 지연)나 프레임 진행이 필요한 테스트만 PlayMode 에 둔다.
  • 그 외 모든 테스트는 EditMode 에 둔다(실행 속도가 훨씬 빠르다).
  • 새 테스트 파일을 추가할 때 반드시 EditMode/PlayMode 중 맞는 폴더에 넣을 것 — 잘못된 폴더에 두면 Unity Test Runner 가 해당 모드에서 테스트를 인식하지 못한다.

알려진 제약 (Runtime 문제, 미수정)

PlayMode 진입 시 RootBootstrap.Initialize()(회피 불가)가 RootScope.cs 의 DI 등록 누락 (ConfigCache 미등록)으로 실패해 TickRunner.Update() 가 매 프레임 NullReferenceException 을 로그로 남긴다. 이로 인해 현재 모든 PlayMode 테스트는 SetUp 단계에서 실패한다. 근본 해결은 RootScope.csConfigCache DI 등록을 추가하는 것이며, Runtime 코드 변경이 필요하다.

2. AAA Pattern

모든 테스트 메서드는 Arrange / Act / Assert 3 구획을 주석으로 명시한다.

[Test]
public void SetBaseValue_NewStat_ReturnsGivenValue()
{
    // Arrange
    var stat = new StatSystem();
    var id = new StatId("Health");

    // Act
    stat.SetBaseValue(EntityId, id, 10f);

    // Assert
    Assert.AreEqual(10f, stat.GetValue(EntityId, id));
}

Regression Test 는 AAA 대신 Given/When/Then 네이밍을 메서드명에 사용한다(4번 참고).

3. Fixture 사용법

기반 클래스 위치 용도
FrameworkTestBase Shared 최상위 추상 기반(공용 로직 없음, 명명 규칙 문서화 목적)
FrameworkEditModeTestBase Shared Scene/GameObject 불필요한 순수 로직, new 로 생성 가능한 System
FrameworkPlayModeTestBase Shared 실시간 대기/프레임 진행이 필요한 테스트
SystemTestFixture Shared FrameworkEditModeTestBase 를 상속하는 System 테스트 전용 별칭
RegressionTestBase EditMode/Regression Regression Test 전용(SystemTestFixture 상속)

SetUp/TearDown 을 override 할 때는 반드시 base.SetUp()/base.TearDown() 을 호출한다.

4. System Test 작성법

  • 테스트 대상 System 을 new 로 직접 생성한다(Framework System 은 생성자 DI 이므로 Reflection/컨테이너 불필요).
  • 실제 Framework 구현체(NewtonsoftJsonAdapter, MemoryPackAdapter 등)를 우선 사용한다. Mock 은 실제 구현을 쓰기 어려운 경우(예: IMessageBus)에만 최소한으로 사용한다.
  • System 이 정상 설계상 Log.Error/Log.Exception 을 남기는 경로를 테스트할 때는 반드시 UnityEngine.TestTools.LogAssert.Expect(...) 로 그 로그를 명시적으로 기대한다. 그렇지 않으면 Unity Test Runner 가 예상치 못한 로그로 간주해 테스트를 자동 실패 처리한다.
  • DiagnosticsCounters 는 Pull 기반(0.5초 SampleInterval)이다. Register 직후 값을 확인하려면 DiagnosticsCounters.Tick(1f) (SampleInterval 초과 deltaTime)을 먼저 호출해 강제 샘플링한다.
  • StatOnValueChanged 계열 이벤트는 Lazy 재계산 방식이라, SetBaseValue 직후 곧바로 이벤트가 발생하지 않는다. GetValue(FinalValue 조회)를 한 번 호출해 재계산을 트리거해야 한다.
  • Addressables/AudioMixer/Locale 등 프로젝트에 실제 리소스·설정이 구성되지 않은 영역은 성공 경로를 검증할 수 없다. 이 경우 실패 경로(유효성 검사, 미존재 키 처리)만 다루고 XML <remarks> 에 범위 한계와 사유를 명시한다.

5. Integration Test 작성법

  • Assets/_Framework/Tests/EditMode/Integration/ 에 둔다.
  • 두 System 을 각각 new 로 생성하고, Framework 가 제공하지 않는 결합(예: Effect -> Stat)은 테스트 메서드 내부에서 이벤트 구독으로 직접 오케스트레이션한다(신규 Runtime 결합 코드 작성 금지).
  • Reflection 사용 금지, Runtime 코드 수정 금지.

6. Regression Test 작성법

  • Assets/_Framework/Tests/EditMode/Regression/RegressionTestBase 를 상속해 작성한다.
  • 클래스명: Regression_<System>_<이슈요약>Tests
  • 메서드명: Given_<사전조건>_When_<행동>_Then_<기대결과> 형태.
  • XML <remarks> 에 발생 시점/증상/원인/수정 내용을 반드시 기록한다.
  • 예제: Regression_DiagnosticsCounters_GetLatestRequiresTickTests.cs

7. Performance Test 작성법

  • Assets/_Framework/Tests/EditMode/Performance/ 에 둔다.
  • System.Diagnostics.Stopwatch 로 측정하고, Pass/Fail 판정 없이 UnityEngine.Debug.Log 로 참고용 수치만 출력한다(기존 PerformanceBenchmarks.cs 패턴을 따른다).
  • 실제 파일 I/O 등 비용이 큰 작업은 반복 횟수를 낮춘다(예: SaveSystem 200회).

8. Test Report 확인

Tools > Framework > Test Report 메뉴에서:

  • EditMode/PlayMode 각각 실행 및 최근 결과 확인
  • System별 테스트 수/PASS/FAIL 확인(테스트 개수 기반 근사치)
  • TestResults.xml 바로 열기

정밀 라인/브랜치 커버리지가 필요하면 Unity Test Coverage 패키지(설치됨)를 배치모드로 실행한다:

Unity.exe -projectPath <path> -batchmode -testPlatform editmode -runTests ^
  -debugCodeOptimization -enableCodeCoverage ^
  -coverageResultsPath <path> -coverageOptions generateHtmlReport;generateBadgeReport -quit

9. 공통 원칙

  • Reflection 사용 금지 (Framework.Tests.* 어셈블리에는 InternalsVisibleTo 가 허용되어 있어 internal 멤버는 직접 접근 가능하다 — Reflection 이 필요 없다)
  • Thread.Sleep 금지 — PlayMode 는 yield return new WaitForSeconds(...), EditMode 는 실시간 대기를 피하고 필요 시 internal API(Tick 등)로 즉시 트리거한다.
  • Mock 최소화 — 실제 Framework 구현을 우선 사용하고, 미사용 Mock 은 주기적으로 점검해 제거한다.