agile test driven development for games what, why, and how

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

Upload: ryan-park

Post on 20-Jun-2015

2.711 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: Agile Test Driven Development For Games What, Why, And How

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

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

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

Page 2: Agile Test Driven Development For Games What, Why, And How

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

Page 3: Agile Test Driven Development For Games What, Why, And How

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

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

Page 4: Agile Test Driven Development For Games What, Why, And How

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: Agile Test Driven Development For Games What, Why, And How
Page 6: Agile Test Driven Development For Games What, Why, And How

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

Page 7: Agile Test Driven Development For Games What, Why, And How

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

테스트 실패테스트 실패

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

체크 인체크 인

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: Agile Test Driven Development For Games What, Why, And How

장점 : 단순함과 모듈화

Page 9: Agile Test Driven Development For Games What, Why, And How

장점 : 안전망

Page 10: Agile Test Driven Development For Games What, Why, And How

장점 : 즉각적인 피드백

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

Page 11: Agile Test Driven Development For Games What, Why, And How
Page 12: Agile Test Driven Development For Games What, Why, And How

장점 : 문서화

Page 13: Agile Test Driven Development For Games What, Why, And How

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

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

Page 14: Agile Test Driven Development For Games What, Why, And How

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

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

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

Page 15: Agile Test Driven Development For Games What, Why, And How

캐릭터 + 방패

Character

Damage(x)

Shield

Damage(x)

class Character{

IShield* m_shield;public:

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

};

Page 16: Agile Test Driven Development For Games What, Why, And How

3 가지 검사 방법

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

Page 17: Agile Test Driven Development For Games What, Why, And How

반환되는 값 검사

TEST (ShieldCanBeDamagedIfFull){

}

방패방패 검사하기

bool Damage()데미지 ?

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

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

Page 18: Agile Test Driven Development For Games What, Why, And How

상태 검사

TEST (LevelCannotBeDamagedBelowZero){

}

방패방패 검사하기

Damage(200)

GetLevel()

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

0?

Page 19: Agile Test Driven Development For Games What, Why, And How

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

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

Page 20: Agile Test Driven Development For Games What, Why, And How

검사를 작성하기

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

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

Page 21: Agile Test Driven Development For Games What, Why, And How

매 빌드마다 검사하기

Page 22: Agile Test Driven Development For Games What, Why, And How

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

캐릭터 검사하기 캐릭터

Damage()

*m_shield

TEST(CharacterUsesShieldToAbsorbDamage){

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

}

390?

방패

GetHealth()

화려한방패

Page 23: Agile Test Driven Development For Games What, Why, And How

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: Agile Test Driven Development For Games What, Why, And How

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: Agile Test Driven Development For Games What, Why, And How

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

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

코드

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

고양이가 끄집어낸어떤 것

부엌의 싱크대

누가 알겠어

Page 26: Agile Test Driven Development For Games What, Why, And How

최상의 관행 : 간결한 검사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: Agile Test Driven Development For Games What, Why, And How

최상의 관행 : 신속한 검사

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: Agile Test Driven Development For Games What, Why, And How

최상의 관행 : 신속한 검사

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

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

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

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

Page 29: Agile Test Driven Development For Games What, Why, And How

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

g_CollisionWorldSingleton

Page 30: Agile Test Driven Development For Games What, Why, And How

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

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

Page 31: Agile Test Driven Development For Games What, Why, And How

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

Page 32: Agile Test Driven Development For Games What, Why, And How
Page 33: Agile Test Driven Development For Games What, Why, And How

API 전체를 감싸기 (wrap)

Page 34: Agile Test Driven Development For Games What, Why, And How

API 상태를 직접 검사하기

Page 35: Agile Test Driven Development For Games What, Why, And How

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

Page 36: Agile Test Driven Development For Games What, Why, And How

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

HavokRenderWare

UnrealNovodexOpenGLDirectX

Page 37: Agile Test Driven Development For Games What, Why, And How

기존의 엔진에서 TDD 하기

Page 38: Agile Test Driven Development For Games What, Why, And How

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

Page 39: Agile Test Driven Development For Games What, Why, And How

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

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

Page 40: Agile Test Driven Development For Games What, Why, And How

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

다 .

Page 41: Agile Test Driven Development For Games What, Why, And How

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: Agile Test Driven Development For Games What, Why, And How

예시 : 캐릭터의 행동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: Agile Test Driven Development For Games What, Why, And How

구조의 선택

Page 44: Agile Test Driven Development For Games What, Why, And How

교훈 #2: TDD 와 코드 설계

Page 45: Agile Test Driven Development For Games What, Why, And How

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

Page 46: Agile Test Driven Development For Games What, Why, And How

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

Page 47: Agile Test Driven Development For Games What, Why, And How

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

Page 48: Agile Test Driven Development For Games What, Why, And How

교훈 #6: 개발 속도

Page 49: Agile Test Driven Development For Games What, Why, And How

교훈 #7: TDD 를 도입하기

Page 50: Agile Test Driven Development For Games What, Why, And How

교훈 #7: TDD 도입하기

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

Page 51: Agile Test Driven Development For Games What, Why, And How

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

5. 5. 결론결론

Page 52: Agile Test Driven Development For Games What, Why, And How

결론

Page 53: Agile Test Driven Development For Games What, Why, And How

질문 ?

자료자료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]