53
게게게 게게 게게게 게게 게게 : 게게게 , 게 게게게 게게게 ? Noel Llopis Senior Architect High Moon Studios 게게 : 게게 http:// ParkPD.egloos.com 게게 : 게게게 http://betterways.tistory.com/

게임을 위한 테스트 주도 개발 : 무엇을 , 왜 그리고 어떻게 ?

  • Upload
    nikki

  • View
    78

  • Download
    6

Embed Size (px)

DESCRIPTION

게임을 위한 테스트 주도 개발 : 무엇을 , 왜 그리고 어떻게 ?. Noel Llopis Senior Architect High Moon Studios 번역 : 박일 http://ParkPD.egloos.com 도움 : 김기웅 http://betterways.tistory.com/. 1. 테스트 주도 개발 ( TDD) 이란 ? 2. 우리는 TDD 를 어떻게 사용했는가 3. TDD 와 게임 4. 우리가 얻은 교훈들 5. 결론. 1. 테스트 주도 개발 (TDD) 이란 ? - PowerPoint PPT Presentation

Citation preview

Page 1: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

게임을 위한 테스트 주도 개발 :

무엇을 , 왜 그리고 어떻게 ?Noel LlopisSenior ArchitectHigh Moon Studios

번역 : 박일 http://ParkPD.egloos.com도움 : 김기웅 http://betterways.tistory.com/

Page 2: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

1. 1. 테스트 주도 개발테스트 주도 개발 ((TDD)TDD) 이란이란 ??2. 2. 우리는 우리는 TDDTDD 를 어떻게 사용했는가를 어떻게 사용했는가3. TDD3. TDD 와 게임와 게임4. 4. 우리가 얻은 교훈들우리가 얻은 교훈들5. 5. 결론결론

Page 3: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

1. 1. 테스트 주도 개발테스트 주도 개발 (TDD)(TDD)이란이란 ?? (( 그리고 어쩌다 이것을 도입하게 되었는가에 대하여그리고 어쩌다 이것을 도입하게 되었는가에 대하여 ))

2. 2. 우리는 우리는 TDDTDD 를 어떻게 사용했는가를 어떻게 사용했는가3. TDD3. TDD 와 게임와 게임4. 4. 우리가 얻은 교훈들우리가 얻은 교훈들5. 5. 결론결론

Page 4: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

define G(n) int n(int t, int q, int d)#define X(p,t,s) (p>=t&&p<(t+s)&&(p-(t)&1023)<(s&1023))#define U(m) *((signed char *)(m))#define F if(!--q){#define I(s) (int)main-(int)s#define P(s,c,k) for(h=0; h>>14==0; h+=129)Y(16*c+h/1024+Y(V+36))&128>>(h&7)?U(s+(h&15367))=k:kG (B){ Z; F D = E (Y (V), C = E (Y (V), Y (t + 4) + 3, 4, 0), 2, 0); Y (t + 12) = Y (t + 20) = i; Y (t + 24) = 1; Y (t + 28) = t; Y (t + 16) = 442890; Y (t + 28) = d = E (Y (V), s = D * 8 + 1664, 1, 0); for (p = 0; j < s; j++, p++) U (d + j) = i == D | j < p ? p--, 0 : (n = U (C + 512 + i++)) < ' ' ? p |= n * 56 - 497, 0 : n;}n = Y (Y (t + 4)) & 1;FU (Y (t + 28) + 1536) |=62 & -n;MU (d + D) =X (D, Y (t + 12) + 26628, 412162) ? X (D, Y (t + 12) + 27653, 410112) ? 31 : 0 : U (d + D);for (; j < 12800; j += 8) P (d + 27653 + Y (t + 12) + ' ' * (j & ~511) + j % 512, U (Y (t + 28) + j / 8 + 64 * Y (t + 20)), 0);}F if (n) { D = Y (t + 28); if (d - 10) U (++Y (t + 24) + D + 1535) = d; else { for (i = D; i < D + 1600; i++) U (i) = U (i + 64); Y (t + 24) = 1; E (Y (V), i - 127, 3, 0); } }else Y (t + 20) += ((d >> 4) ^ (d >> 5)) - 3;}}

Page 5: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?
Page 6: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

TDD 는 앞서 언급된 문제들을 해결해주었다

Page 7: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

불과 몇 분밖에 불과 몇 분밖에 걸리지 않는다걸리지 않는다 ..

테스트 실패테스트 실패

테스트 통과테스트 통과테스트 통과테스트 통과

체크 인체크 인

TDD 의 순환 과정

TEST (ShieldLevelStartsFull){

Shield shield;CHECK_EQUAL (Shield::kMaxLevel, shield.GetLevel());

}

TEST (ShieldLevelStartsFull){

Shield shield;CHECK_EQUAL (Shield::kMaxLevel, shield.GetLevel());

}Shield::Shield() : m_level (Shield::kMaxLevel){}

Shield::Shield() : m_level (Shield::kMaxLevel){}

테스트작성 코드 작성

리팩토링

Page 8: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

장점 : 단순함과 모듈화

Page 9: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

장점 : 안전망

Page 10: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

장점 : 즉각적인 피드백

마일스톤마일스톤 : ~2: ~2 개월개월주기주기 : 2~4: 2~4 주주야간야간 구축구축 : 1: 1 일일자동 구축자동 구축 : ~1: ~1 시간시간TDDTDD : 30: 30 회 회 / / 3~43~4 분분

Page 11: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?
Page 12: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

장점 : 문서화

Page 13: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

TDD != TDD != 단위 검사단위 검사TDD != TDD != 테스팅 전략테스팅 전략

TDD == TDD == 개발 기법개발 기법

Page 14: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

1. 1. 테스트 주도 개발테스트 주도 개발 (TDD)(TDD) 이란이란 ??

2. 2. 우리는 우리는 TDDTDD 를 어떻게 를 어떻게 사용했는가사용했는가

3. TDD3. TDD 와 게임와 게임4. 4. 우리가 얻은 교훈들우리가 얻은 교훈들5. 5. 결론결론

Page 15: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

캐릭터 + 방패

Character

Damage(x)

Shield

Damage(x)

class Character{

IShield* m_shield;public:

Character();void Damage(float amount);float GetHealth() const;

};

Page 16: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

3 가지 검사 방법

• 반환되는 값을 검사하기반환되는 값을 검사하기• 상태를 검사하기상태를 검사하기• 객체간의 상호작용을 검사하기객체간의 상호작용을 검사하기

Page 17: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

반환되는 값 검사

TEST (ShieldCanBeDamagedIfFull){

}

방패방패 검사하기

bool Damage()데미지 ?

Shield shield;CHECK (shield.Damage());

“ShieldLevelStartsFull 에서 오류 발생 : 100 을 예상했지만 , 0 이 나옴 .”

Page 18: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

상태 검사

TEST (LevelCannotBeDamagedBelowZero){

}

방패방패 검사하기

Damage(200)

GetLevel()

Shield shield;shield.Damage(200);CHECK_EQUAL (0, shield.GetLevel());

0?

Page 19: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

어디에 검사를 삽입하는 게 좋을까 ?

• TestGame.exe (Game.libTestGame.exe (Game.lib 와 연결됨와 연결됨 ))• #ifdef UNIT_TESTS• GameTests.DLLGameTests.DLL• GameTests.upkGameTests.upk

Page 20: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

검사를 작성하기

• 새로운 검사를 추가하기 손쉽도록새로운 검사를 추가하기 손쉽도록 ,, 단위 단위 검사 프레임워크를 사용하라검사 프레임워크를 사용하라

• UnitTest++UnitTest++ 는 게임에 꽤 적합하다는 게임에 꽤 적합하다

Page 21: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

매 빌드마다 검사하기

Page 22: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

상호작용 검사( 초기에 문제가 될 수 있다 .)

캐릭터 검사하기 캐릭터

Damage()

*m_shield

TEST(CharacterUsesShieldToAbsorbDamage){

Character character(400);character.Damage(100);CHECK_EQUAL(390, character.GetHealth());

}

390?

방패

GetHealth()

화려한방패

Page 23: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

class IShield{public:

virtual float Damage(float amount) = 0;}

class FancyShield : public IShield{public:

float Damage(float amount) { … };}

class MockShield : public IShield{public:

float damagePassedIn;float damageToReturn;float Damage(float amount){

damagePassedIn = amount;return damageToReturn;

}}

가짜 객체가 , 검사 대상인 해당 단위 (unit) 의외부에 위치한 객체를 대신한다 .

Page 24: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

Mock 을 사용해서 검사하기캐릭터 검사하기

캐릭터Damage()

*m_shield

TEST(CharacterUsesShieldToAbsorbDamage){

}

매개 변수들은 정확한가 ? 가짜 방패

GetHealth()반환된 데미지가정확하게 사용되는가 ?

MockShield mockShield = new MockShield;mockShield->damageToReturn = 10;Character character(400, mockShield);

character.Damage(200);

CHECK_EQUAL(200, mockShield->damagePassedIn);CHECK_EQUAL(390, character.GetHealth());

Page 25: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

최상의 관행 : 근처의 코드만 검사하기

검사 검사중인코드 검사 검사중인

코드

하위 시스템 A 하위 시스템 B하위 시스템 C

고양이가 끄집어낸어떤 것

부엌의 싱크대

누가 알겠어

Page 26: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

최상의 관행 : 간결한 검사TEST (ShieldStartsAtInitialLevel){

ShieldComponent shield(100);CHECK_EQUAL (100, shield.GetLevel());

}

TEST (ShieldTakesDamage){

ShieldComponent shield(100);shield.Damage(30);CHECK_EQUAL (70, shield.GetLevel());

}

TEST (LevelCannotDropBelowZero){

ShieldComponent shield(100);shield.Damage(200);CHECK_EQUAL (0, shield.GetLevel());

}

TEST(ActorDoesntMoveIfPelvisBodyIsInSamePositionAsPelvisAnim){

component = ConstructObject<UAmpPhysicallyDrivableSkeletalComponent>();component->physicalPelvisHandle = NULL;component->SetOwner(owner);component->SkeletalMesh = skelMesh;component->Animations = CreateReadable2BoneAnimSequenceForAmpRagdollGetup(component, skelMesh,

10.0f, 0.0f);component->PhysicsAsset = physicsAsset;component->SpaceBases.AddZeroed(2);component->InitComponentRBPhys(false);component->LocalToWorld = FMatrix::Identity;const FVector actorPos(100,200,300);const FVector pelvisBodyPositionWS(100,200,380);const FTranslationMatrix actorToWorld(actorPos);owner->Location = actorPos;component->ConditionalUpdateTransform(actorToWorld);INT pelvisIndex = physicsAsset->CreateNewBody(TEXT("Bone1"));URB_BodySetup* pelvisSetup = physicsAsset->BodySetup(pelvisIndex);FPhysAssetCreateParams params = GetGenericCreateParamsForAmpRagdollGetup();physicsAsset->CreateCollisionFromBone( pelvisSetup,

skelMesh,1,params,boneThings);

URB_BodyInstance* pelvisBody = component->PhysicsAssetInstance->Bodies(0);NxActor* pelvisNxActor = pelvisBody->GetNxActor();SetRigidBodyPositionWSForAmpRagdollGetup(*pelvisNxActor, pelvisBodyPositionWS);

component->UpdateSkelPose(0.016f);component->RetransformActorToMatchCurrrentRoot(TransformManipulator());

const float kTolerance(0.002f);

FMatrix expectedActorMatrix;expectedActorMatrix.SetIdentity();expectedActorMatrix.M[3][0] = actorPos.X;expectedActorMatrix.M[3][1] = actorPos.Y;expectedActorMatrix.M[3][2] = actorPos.Z;const FMatrix actorMatrix = owner->LocalToWorld();CHECK_ARRAY2D_CLOSE(expectedActorMatrix.M, actorMatrix.M, 4, 4, kTolerance);

}

Page 27: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

최상의 관행 : 신속한 검사

Slow Test(24 > 20 ms): CheckSpotOverlapIsHandledCorrectly1TestSlow Test(25 > 20 ms): CheckSpotOverlapIsHandledCorrectly2TestSlow Test(24 > 20 ms): DeleteWaveEventFailsIfEventDoesntExistInCueTestSlow Test(22 > 20 ms): CanGetObjectsInBrowserListPackageTestSlow Test(48 > 20 ms): HmAddActorCallsCreateActorTestSlow Test(74 > 20 ms): HmReplaceActorDoesNothingIfEmptySelectionTestSlow Test(57 > 20 ms): HmReplaceActorWorksIfTwoActorsSelectedTestSlow Test(26 > 20 ms): ThrowExceptionWhenTrackIndexOutOfRangeTest

1923 회 검사의 총소요 시간 : 4.83 초 .

26 회의 느린 검사에 소요된 시간 : 2.54 초 .

Page 28: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

최상의 관행 : 신속한 검사

Debug 상태에서 TestDebugServer 의 단위 검사 실행중 ..검사 116 번 실행실패한 검사 없음 . 소요 시간 : 0.016 초 .

Debug 상태에서 TestStreams 의 단위 검사 실행중 ...검사 138 번 실행실패한 검사 없음 . 소요 시간 : 0.015 초 .

Debug 상태에서 TestMath 의 단위 검사 실행중 ...검사 245 번 실행실패한 검사 없음 . 소요 시간 : 0.001 초 .

단위 검사 실행중 ...검사 184 번 실행실패한 검사 없음 . 소요 시간 : 0.359 초 .

Page 29: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

최상의 관행 : 비의존적인 검사

g_CollisionWorldSingleton

Page 30: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

1. 1. 테스트 주도 개발테스트 주도 개발 (TDD)(TDD) 이란이란 ??2. 2. 우리는 우리는 TDDTDD 를 어떻게 사용했는가를 어떻게 사용했는가

3. TDD3. TDD 와 게임와 게임4. 4. 우리가 얻은 교훈들우리가 얻은 교훈들5. 5. 결론결론

Page 31: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

콘솔의 경우 , PC 보다는 덜 자주 검사했다 .

Page 32: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?
Page 33: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

API 전체를 감싸기 (wrap)

Page 34: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

API 상태를 직접 검사하기

Page 35: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

API 함수 호출을 제외한 모든 코드를 검사하기

Page 36: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

미들웨어까지 포함해서 검사하기

HavokRenderWare

UnrealNovodexOpenGLDirectX

Page 37: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

기존의 엔진에서 TDD 하기

Page 38: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

TDD 를 해보고는 싶지만 ...

Page 39: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

1. TDD 1. TDD 란란 ??2. TDD 2. TDD 사용법사용법3. TDD3. TDD 와 게임와 게임

4. 4. 우리가 얻은 교훈들우리가 얻은 교훈들5. 5. 결론결론

Page 40: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

교훈 #1: 고수준의 게임 코드에도 TDD 를 적용할 수 있

다 .

Page 41: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

function TestEnemyChoosesLightAttack(){

FightingComp = new(self) class'FightingComponent';

FightingComp.AddAttack(LightAttack);FightingComp.AddAttack(HeavyAttack);

enemy.AttachComponent(FightingComp);enemy.FightingComponent = FightingComp;enemy.FindPlayerPawn = MockFindPlayerPawn;enemy.ShouldMeleeAttack = MockShouldAttack;ShouldMeleeAttackReturn = true;

enemy.Tick(0.666);

CheckObjectsEqual(LightAttack,FightingComp.GetCurrentAttack());

}

예시 : 공격형 인공지능

Page 42: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

예시 : 캐릭터의 행동TEST_F( CharacterFixture,

SupportedWhenLeapAnimationEndsTransitionsRunning ){

LandingState state(CharacterStateParameters(&character), AnimationIndex::LeapLanding);

state.Enter(input);input.deltaTime = character.GetAnimationDuration(

AnimationIndex::LeapLanding ) + kEpsilon;

character.supported = true;CharacterStateOutput output = state.Update( input );CHECK_EQUAL(std::string("TransitionState"),

output.nextState->GetClassInfo().GetName());const TransitionState& transition = *output.nextState;CHECK_EQUAL(std::string("RunningState"),

transition.endState->GetClassInfo().GetName());}

Page 43: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

구조의 선택

Page 44: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

교훈 #2: TDD 와 코드 설계

Page 45: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

교훈 #3: 검사 횟수는 프로젝트 진행의 척도가 될 수 있다

Page 46: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

교훈 #4: TDD 는 빌드의 안정성을 높여준다

Page 47: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

교훈 #5: TDD 는 더 많은 코드를 만들어 낸다

Page 48: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

교훈 #6: 개발 속도

Page 49: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

교훈 #7: TDD 를 도입하기

Page 50: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

교훈 #7: TDD 도입하기

위험할수록위험할수록 ,, 대가가 크다대가가 크다(High risk – High reward)(High risk – High reward)

Page 51: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

1. 1. 테스트 주도 개발테스트 주도 개발 (TDD)(TDD) 이란이란 ??2. 2. 우리는 우리는 TDDTDD 를 어떻게 사용했는가를 어떻게 사용했는가3. TDD3. TDD 와 게임와 게임4. 4. 우리가 얻은 교훈들우리가 얻은 교훈들

5. 5. 결론결론

Page 52: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

결론

Page 53: 게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ?

질문 ?

자료자료Games from Within Games from Within http://www.gamesfromwithin.com 위 위 SiteSite 에는 이 강연의 보다 자세한 발표 자료와에는 이 강연의 보다 자세한 발표 자료와 TDD TDD 및 및

UnitTest++ UnitTest++ 프레임워크에 대한 자료가 있다프레임워크에 대한 자료가 있다 ..[[ 역자주역자주 ]]

http://andstudy.com/andwiki/wiki.php/BackwardsIsForward이 내용에 대한 이 내용에 대한 Note Note 가 번역된 페이지입니다가 번역된 페이지입니다 . .

참고하세요참고하세요 ..

Noel Llopis - Noel Llopis - [email protected]