Unity Test Framework — 유닛 테스트와 플레이 모드 테스트
Unity Test Framework(UTF)는 NUnit 기반의 공식 테스트 솔루션입니다. EditMode 테스트(빠른 유닛 테스트)와 PlayMode 테스트(씬 실행 테스트) 두 가지 모드를 지원합니다.
1. 설치 및 폴더 구조
섹션 제목: “1. 설치 및 폴더 구조”Package Manager → Unity Registry → Test Framework → InstallAssets/ Tests/ EditMode/ ← EditMode 테스트 폴더 Tests.asmdef ← Assembly Definition (testPlatforms: Editor) PlayMode/ ← PlayMode 테스트 폴더 Tests.asmdef ← Assembly Definition (testPlatforms: PlayMode)2. EditMode 테스트 — 유닛 테스트
섹션 제목: “2. EditMode 테스트 — 유닛 테스트”using NUnit.Framework;
public class DamageCalculatorTests{ private DamageCalculator _calc;
[SetUp] public void Setup() { _calc = new DamageCalculator(); }
[Test] public void Calculate_WithCriticalHit_ReturnDoubledDamage() { float result = _calc.Calculate(baseDamage: 100f, isCritical: true); Assert.AreEqual(200f, result, delta: 0.01f); }
[Test] [TestCase(100f, false, 100f)] [TestCase(100f, true, 200f)] [TestCase(0f, true, 0f)] public void Calculate_VariousInputs(float base_, bool crit, float expected) { Assert.AreEqual(expected, _calc.Calculate(base_, crit), 0.01f); }}3. PlayMode 테스트 — 코루틴 테스트
섹션 제목: “3. PlayMode 테스트 — 코루틴 테스트”using System.Collections;using NUnit.Framework;using UnityEngine;using UnityEngine.TestTools;
public class PlayerMovementTests{ private GameObject _playerObj;
[SetUp] public void Setup() { _playerObj = new GameObject("Player"); _playerObj.AddComponent<PlayerMovement>(); _playerObj.AddComponent<CharacterController>(); }
[TearDown] public void Teardown() { Object.Destroy(_playerObj); }
[UnityTest] public IEnumerator MoveForward_AfterOneSecond_MovesExpectedDistance() { var movement = _playerObj.GetComponent<PlayerMovement>(); movement.MoveInput = Vector2.up;
yield return new WaitForSeconds(1f);
float moved = _playerObj.transform.position.z; Assert.Greater(moved, 4.5f, "1초 후 5m 이동해야 함"); }}4. 씬 로드 PlayMode 테스트
섹션 제목: “4. 씬 로드 PlayMode 테스트”using UnityEngine.SceneManagement;using UnityEngine.TestTools;
public class GameSceneTests{ [UnitySetUp] public IEnumerator LoadScene() { SceneManager.LoadScene("GameScene"); yield return null; // 씬 로드 대기 }
[UnityTest] public IEnumerator EnemySpawner_SpawnsCorrectCount() { yield return new WaitForSeconds(2f); var enemies = Object.FindObjectsByType<Enemy>(FindObjectsSortMode.None); Assert.AreEqual(5, enemies.Length); }}5. 인터페이스 기반 모킹 패턴
섹션 제목: “5. 인터페이스 기반 모킹 패턴”UTF는 NSubstitute를 공식 지원하지 않지만, 인터페이스를 이용한 수동 모킹으로 의존성을 분리할 수 있습니다.
// 인터페이스 정의public interface IScoreService{ int GetHighScore(string playerId); void SaveScore(string playerId, int score);}
// 테스트용 Fakepublic class FakeScoreService : IScoreService{ private readonly Dictionary<string, int> _scores = new(); public int GetHighScore(string id) => _scores.GetValueOrDefault(id, 0); public void SaveScore(string id, int score) => _scores[id] = score;}
// 테스트[Test]public void PlayerController_SavesHighScore_WhenScoreExceedsPrevious(){ var scoreService = new FakeScoreService(); var controller = new PlayerController(scoreService);
controller.AddScore(500); controller.EndGame("player1");
Assert.AreEqual(500, scoreService.GetHighScore("player1"));}6. LogAssert — 로그 검증
섹션 제목: “6. LogAssert — 로그 검증”using UnityEngine.TestTools;
[Test]public void InvalidInput_LogsError(){ LogAssert.Expect(LogType.Error, "Invalid input value"); _system.Process(-1); // 내부에서 Debug.LogError 호출 예상}7. CLI 실행 (CI/CD 연동)
섹션 제목: “7. CLI 실행 (CI/CD 연동)”# 커맨드라인 테스트 실행Unity -runTests \ -projectPath /path/to/project \ -testPlatform EditMode \ -testResults results.xml \ -batchmode -nographics -quitGitHub Actions 예시:
- name: Run Unity Tests run: | $UNITY_PATH -runTests -projectPath . \ -testPlatform EditMode \ -testResults results/results.xml \ -batchmode -nographicsEditMode 테스트로 게임 로직을 빠르게 검증하고, PlayMode 테스트로 씬 기반 통합 시나리오를 검증하세요. 인터페이스 기반 설계와 Fake 객체를 조합하면 Unity의 MonoBehaviour 의존성 없이도 핵심 로직을 테스트할 수 있습니다.