agd test driven development for games what, why, and how)(game connect 2006)[200611] korean

53
테테테 테테 테테 : 테테테 테 , 테테테 ? Noel Llopis Senior Architect High Moon Studios 테테 : 테테 http://ParkPD.egloos.com [email protected]

Upload: ryan-park

Post on 20-Jun-2015

1.804 views

Category:

Technology


5 download

TRANSCRIPT

Page 1: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

테스트 주도 개발 : 무엇을 왜 , 어떻게 ?

Noel LlopisSenior ArchitectHigh Moon Studios

번역 : 박일http://[email protected]

Page 2: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

1. TDD1. TDD 란란 ? ?

2. TDD 2. TDD 쓰는 법쓰는 법 ??

3. TDD 3. TDD 와 게임와 게임4. 4. 배운 점배운 점5. 5. 결론결론

Page 3: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

1. TDD1. TDD 란란 ? ? (( 왜 이걸 쓰고 싶어할까왜 이걸 쓰고 싶어할까 ??))

2. TDD2. TDD 쓰는 법쓰는 법3. TDD 3. TDD 와 게임와 게임4. 4. 배운 점배운 점5. 5. 결론결론

Page 4: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

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: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean
Page 6: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

TDD 는 이런 문제점에 초점이 맞춰져 있다 .

Page 7: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

몇 분 안에 진행몇 분 안에 진행

테스트 실패테스트 실패

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

체크인Check in

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: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

좋은 점 : 단순함 , 모듈화

Page 9: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

좋은 점 : 안전망

Page 10: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

좋은 점 : Instant feedback

마일스톤마일스톤 : ~2 : ~2 개월개월주기주기 : 2-4 : 2-4 주주Nightly Nightly 빌드빌드 : 1 : 1 일일자동 빌드자동 빌드 : ~1 : ~1 시간시간TDD: 3-4 TDD: 3-4 분간에 분간에 30 30 여번여번

Page 11: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean
Page 12: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

좋은 점 : 문서화

Page 13: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

TDD != TDD != 단위 테스트단위 테스트TDD != TDD != 테스트 방법테스트 방법

TDD == TDD == 개발 방법론개발 방법론

Page 14: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

1. TDD1. TDD 란란 ??

2. TDD2. TDD 쓰는 법쓰는 법3. TDD 3. TDD 와 게임와 게임4. 4. 배운 점배운 점5. 5. 결론결론

Page 15: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

캐릭터 + 방패

Character

Damage(x)

Shield

Damage(x)

class Character{

IShield* m_shield;public:

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

};

Page 16: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

3 가지 테스트 방법

• 리턴 값 검사리턴 값 검사• 상태 검사상태 검사• 객체 상호작용 검사객체 상호작용 검사

Page 17: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

리턴값 검사

TEST (ShieldCanBeDamagedIfFull){

}

ShieldTest Shield

bool Damage()Damage?

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

“Failure in ShieldLevelStartsFull: Expected 100 but got 0”

Page 18: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

상태 검사

TEST (LevelCannotBeDamagedBelowZero){

}

ShieldTest Shield

Damage(200)

GetLevel()

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

0?

Page 19: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

어디에 테스트를 둘까 ?

• TestGame.exe (links with Game.lib)TestGame.exe (links with Game.lib)• #ifdef UNIT_TESTS#ifdef UNIT_TESTS• GameTests.DLLGameTests.DLL• GameTests.upkGameTests.upk

Page 20: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

테스트 작성

• 테스트를 쉽게 추가하기 위해 단위 테스트 테스트를 쉽게 추가하기 위해 단위 테스트 프레임워크를 사용프레임워크를 사용

• UnitTest++ UnitTest++ 는 게임에 잘 맞아떨어짐는 게임에 잘 맞아떨어짐 ..

Page 21: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

매 빌드마다 테스트 돌리기

Page 22: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

테스트 상호작용( 문제가 될 수 있는 부분 )

Test Character Character

Damage()

*m_shield

TEST(CharacterUsesShieldToAbsorbDamage){

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

}

390?

Shield

GetHealth()

FancyShield

Page 23: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

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;

}}

A mock object stands in for an objectoutside the unit you're testing

Page 24: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

테스트에 Mock 쓰기

Test Character Character

Damage()

*m_shield

TEST(CharacterUsesShieldToAbsorbDamage){

}

MockShield Parameters correct?

GetHealth()Returned damagecorrectly used?

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: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

실천법 : 가까이 있는 코드만 테스트하기

TestCodeundertest

TestCodeundertest

Subsystem A Subsystem BSubsystem C

Something the catdragged in

The kitchen sink

Who knows

Page 26: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

Best Practices: Keep Tests SimpleTEST (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: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

실천법 : 테스트를 빠르게 유지하기

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

Total time spent in 1923 tests: 4.83 seconds.

Time spent in 26 slow tests: 2.54 seconds.

Page 28: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

실천법 : 테스트를 빠르게 유지하기

Running unit tests TestDebugServer in Debug...116 tests runThere were no test failures. Test time: 0.016 seconds.

Running unit tests for TestStreams in Debug...138 tests runThere were no test failures. Test time: 0.015 seconds.

Running unit tests TestMath in Debug...245 tests runThere were no test failures. Test time: 0.001 seconds.

Running unit tests...184 tests runThere were no test failures. Test time: 0.359 seconds.

Page 29: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

실천법 : 테스트를 독립적으로 유지하기

g_CollisionWorldSingleton

Page 30: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

1. TDD1. TDD 란란 ??

2. TDD 2. TDD 쓰는 법쓰는 법

3. TDD 3. TDD 와 게임와 게임4. 4. 배운 점배운 점5. 5. 결론결론

Page 31: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

콘솔에서는 테스트를 덜 자주 돌렸습니다 .

Page 32: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean
Page 33: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

전체 API 를 wrap 하기

Page 34: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

API 상태를 직접 테스트하기

Page 35: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

API 함수 호출 뺀 나머지 코드를 테스트하기

Page 36: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

미들웨어를 끼고 테스트하기

HavokRenderWare

UnrealNovodexOpenGLDirectX

Page 37: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

만들어진 엔진을 끼고 TDD 하기

Page 38: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

TDD 를 해 보고 싶지만 ...

Page 39: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

1. TDD 1. TDD 란란 ??

2. TDD 2. TDD 사용법사용법3. TDD 3. TDD 와 게임와 게임

4. 4. 배운 점배운 점5. 5. 결론결론

Page 40: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

교훈 #1: TDD 는 고수준 게임 코드에도 사용될 수 있다 .

Page 41: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

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: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

캐릭터 행동의 예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: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

구조의 선택

Page 44: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

교훈 #2: TDD 와 코드 디자인

Page 45: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

교훈 #3: 테스트 개수로 작업 진행 상황 알기

Page 46: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

교훈 #4: 빌드 안정성을 높여주는 TDD

Page 47: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

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

Page 48: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

교훈 #6: 개발 속도

Page 49: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

교훈 #7: TDD 도입하기

Page 50: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

교훈 #7: TDD 도입하기

High risk – High rewardHigh risk – High reward

Page 51: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

1. TDD1. TDD 란란 ??

2. TDD 2. TDD 쓰는 법쓰는 법3. TDD 3. TDD 와 게임와 게임4. 4. 배운 점배운 점

5. 5. 결론결론

Page 52: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

결론

Page 53: Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006)[200611] Korean

질문 ?

ResourcesResourcesGames from Within Games from Within http://www.gamesfromwithin.comhttp://www.gamesfromwithin.com

Includes paper for this presentation with more details and Includes paper for this presentation with more details and links to other TDD resources and the UnitTest++ links to other TDD resources and the UnitTest++ framework.framework.

Noel Llopis - Noel Llopis - [email protected]