in 게임 개발 노트

유니티 TDD 포교한것을 살짝 후회

역시 기술은 끝까지 써봐야 제대로 말하고 추천하고 다닐 자격이 있는 것 같다.

TDD 뽕 맞아서 게임 개발에도 적용해야지~ 하면서 추천하고 다녔는데 결국 나도 안쓰게됬다. 테스트 자체는 유용하지만, 테스트 작성이 구현보다 우선되야 한다는 정공법이 게임 개발(정확히는 엔진 위에서 작성하는 경우)에는 그대로 적용할 수 없다는 특수성을 인정하게되었다.

좀 부끄럽다. 스스로를 속이면서 “내가 테스트 코드를 못짜는거야”라고 버티면서 테스트 우선으로 유니티 프로젝트 적용해보려 했는데 으윽…

유닛 테스트랑 게임 개발은 아직 안어울리는 것 같다.

물론 테스트 자동화 자체는 굉장히 유용하기 때문에 매크로 돌리는 느낌으로 사용하면 어떠한 수동 테스트보다 무조건 편하다. 하지만 구현보다 테스트 먼저하는 식의 개발은 당장 적용하긴 무리.

유닛 테스트 짤이라고해서, 사람 몸 머리 다리를 쪼개서 테스트하는 유머짤이 돌아다녔는데 그렇게 테스트 단위를 명확하게 쪼갤수 있으면 좋다. 근데 안된다. 게임엔진 위에서는 테스트 단위를 가볍게 유지하기 힘들다.

게임은 프레임 기반이라서 성능과 시간에 민감하다. 그리고 상호작용을 테스트하면서 테스트 단위가 커지고 외부에 의존적으로 변할 수 밖에 없다.

게임 위의 동작은 시간을 넘긴다는 개념없이는 테스트가 의미가 없었다. 왜냐면 점프키를 눌렀는데 ‘점프’했다는 사실은 별로 중요하지 않았으니까. 그건 너무 쉽게 예측 가능하다.

유닛 테스트는 결과를 예측하기 쉬운 대상을 테스트해야 하는건 맞지만, 게임 개발을 하면서 테스트 하길 원하는 대상은 점프키를 눌렀을때 점프를 했냐가 아니라, 주변의 방해(?)에도 불구하고 점프를 ‘제대로’ 했냐는 것이다.

그럴려면 버그를 일으킬만한 주변 사물들도 점프를 하는 동안 변화가 있어야 한다. 하지만 여기서부터 테스트의 독립성을 유지하는 것은 물건너 갔다. 유닛이 아니라 통합테스트가 된다.

어쨌든 유니티 테스트 도구는 코루틴을 사용해서 시간을 넘기면서 진행할 수 있다. 하지만 시간 개념이 들어가면 테스트 결과에 대한 예측 불가능성이 너무 커진다. 부동소수점과 물리 기반 처리가 들어가면 어쩔수 없는 것이지만.

프레임을 실제로 넘기진 않고, 프레임이 넘어가는 것 자체를 시뮬레이션 하도록 코드를 짤수도 있었다. 시간을 통제할 수 있도록. 하지만 이렇게 까지 테스트 코드를 짜야 하나 싶다.

이미 여기서부터는 쓸데없이 테스트가 커진 상태다.

예측 불가능성을 줄이려면 테스트 코드는 가벼워야 한다. 그런데 게임 엔진은 컴포넌트 기반이다 보니, 컴포넌트는 홀더=게임 오브젝트 없이 존재할수가 없다. 근데 게임 오브젝트는 최소 1프레임의 시간이 흘러야지 자신의 컴포넌트를 초기화하고 사용 가능하게 준비해준다. 근데 그 찰나의 프레임동안 온갖 통제할 수 없는 변수가 다 생김. ^오^

게다가 게임 엔진 위의 코드는 유저 입력 등을 이유로 정적 함수를 많이 사용한다.

테스트에는 테스트 내부에서 실시간으로 생성된 객체만 남아야하는데, 테스트 외부에서 생성된 객체를 끌여와 사용하니, 어떤 테스트의 실행이 다른 테스트의 결과를 바꾸는 경우도 많다. 테스트의 실행 순서가 결과에 영향을 주면 안되는데 주는 경우도 있다 ㅠ

암튼 테스트 타겟에 관한 코드만 테스트에 남기는게 잘 안된다.

의존성 인젝션과 목업 오브젝트를 사용해서 유저 입력을 정적 함수로 부터 받지 않고, 실시간 생성된 객체로 취급할수도 있다. 그러면 테스트 내부에서 유저 입력 그 자체를 생성하고 유저 입력을 이미테이션 할 수 있지만, 그 쯤 되면 편하게 개발하려고 유닛 테스트 한다는 말은 다 물건너 갔다.

  • 박대근

    매우 동감합니다.
    저도 TDD가 좋다좋다 워낙 말이 많아서 바이블인 켄트백의 책도 구입해서 읽고 연습도 하고 했지만 도저히 게임에 적용하기가 힘들어서 내가 못하는가 싶었는데 어느 순간 게임 개발엔 TDD가 맞지 않구나를 깨닫게 됐네요. 지금은 그냥 코드 설계에 관한 식견을 넓혀줬다로 만족하고 있습니다.