SlideShare une entreprise Scribd logo
1  sur  53
게임을 위한 테스트 주도 개발 : 무엇을 ,  왜 그리고 어떻게 ? Noel Llopis Senior Architect High Moon Studios 번역  :  박일  http:// ParkPD.egloos.com 도움  :  김기웅  http://betterways.tistory.com/
[object Object],[object Object],[object Object],[object Object],[object Object]
[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
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:k G (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; F U (Y (t + 28) + 1536) |= 62 & -n; M U (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; } }
 
TDD 는 앞서 언급된 문제들을 해결해주었다
[object Object],TDD 의 순환 과정 체크 인 체크 인 TEST (ShieldLevelStartsFull) { Shield shield; CHECK_EQUAL (Shield::kMaxLevel, shield.GetLevel()); } Shield::Shield() : m_level (Shield::kMaxLevel) { } 테스트 작성 코드 작성 리팩토링 테스트 실패 테스트 통과 테스트 통과
장점 :  단순함과 모듈화
장점 :  안전망
장점 :  즉각적인 피드백 ,[object Object],[object Object],[object Object],[object Object],[object Object]
 
장점 :  문서화
TDD !=  단위 검사 TDD !=  테스팅 전략 TDD ==  개발 기법
[object Object],[object Object],[object Object],[object Object],[object Object]
캐릭터   +  방패 Character Damage(x) Shield Damage(x) class Character { IShield* m_shield; public: Character(); void Damage(float amount); float GetHealth() const; };
3 가지 검사 방법 ,[object Object],[object Object],[object Object]
반환되는 값 검사 TEST (ShieldCanBeDamagedIfFull) { } 방패 방패 검사하기 bool Damage() 데미지 ? Shield shield; CHECK (shield.Damage()); “ ShieldLevelStartsFull 에서 오류 발생 : 100 을 예상했지만 , 0 이 나옴 . ”
상태 검사 TEST (LevelCannotBeDamagedBelowZero) { } 방패 방패 검사하기 Damage(200) GetLevel() Shield shield; shield.Damage(200); CHECK_EQUAL (0, shield.GetLevel()); 0?
어디에 검사를 삽입하는 게 좋을까 ? ,[object Object],[object Object],[object Object],[object Object]
검사를 작성하기 ,[object Object],[object Object]
매 빌드마다 검사하기
상호작용 검사 ( 초기에 문제가 될 수 있다 . ) 캐릭터 검사하기 캐릭터 Damage() *m_shield TEST(CharacterUsesShieldToAbsorbDamage) { Character character(400); character.Damage(100); CHECK_EQUAL(390, character.GetHealth()); } 390? 방패 GetHealth() 화려한 방패
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) 의 외부에 위치한 객체를 대신한다 .
Mock 을 사용해서 검사하기 캐릭터 검사하기 TEST(CharacterUsesShieldToAbsorbDamage) { } 가짜 방패   MockShield mockShield = new MockShield; mockShield->damageToReturn = 10; Character character(400, mockShield); character.Damage(200); CHECK_EQUAL(200, mockShield->damagePassedIn); CHECK_EQUAL(390, character.GetHealth()); 캐릭터 Damage() *m_shield 매개 변수들은 정확한가 ? GetHealth() 반환된 데미지가 정확하게 사용되는가 ?
최상의 관행 :  근처의 코드만 검사하기 검사 검사중인 코드 검사 검사중인 코드 하위 시스템   A 하위 시스템  B 하위 시스템  C 고양이가 끄집어낸 어떤 것 부엌의 싱크대 누가 알겠어
최상의 관행 :  간결한 검사 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(&quot;Bone1&quot;)); 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); }
최상의 관행 :  신속한 검사 Slow Test(24 > 20 ms): CheckSpotOverlapIsHandledCorrectly1Test Slow Test(25 > 20 ms): CheckSpotOverlapIsHandledCorrectly2Test Slow Test(24 > 20 ms): DeleteWaveEventFailsIfEventDoesntExistInCueTest Slow Test(22 > 20 ms): CanGetObjectsInBrowserListPackageTest Slow Test(48 > 20 ms): HmAddActorCallsCreateActorTest Slow Test(74 > 20 ms): HmReplaceActorDoesNothingIfEmptySelectionTest Slow Test(57 > 20 ms): HmReplaceActorWorksIfTwoActorsSelectedTest Slow Test(26 > 20 ms): ThrowExceptionWhenTrackIndexOutOfRangeTest 1923 회 검사의 총소요 시간 :  4.83 초 . 26 회의 느린 검사에 소요된 시간 :  2.54 초 .
최상의 관행 :  신속한 검사 Debug  상태에서  TestDebugServer 의 단위 검사 실행중 .. 검사  116 번 실행 실패한 검사 없음 .   소요 시간 : 0.016 초 . Debug  상태에서  TestStreams 의 단위 검사 실행중 ... 검사  138 번 실행 실패한 검사 없음 .   소요 시간 : 0.015 초 . Debug  상태에서  TestMath 의 단위 검사 실행중 ... 검사  245 번 실행 실패한 검사 없음 .   소요 시간 : 0.001 초 . 단위 검사 실행중 ... 검사  184 번 실행 실패한 검사 없음 .   소요 시간 : 0.359 초 .
최상의 관행 :  비의존적인 검사 g_CollisionWorldSingleton
[object Object],[object Object],[object Object],[object Object],[object Object]
콘솔의 경우 , PC 보다는 덜 자주 검사했다 .
 
API  전체를 감싸기 (wrap)
API  상태를 직접 검사하기
API  함수 호출을 제외한 모든 코드를 검사하기
미들웨어까지 포함해서 검사하기 Havok RenderWare Unreal Novodex OpenGL DirectX
기존의 엔진에서  TDD 하기
TDD 를 해보고는 싶지만 ...
[object Object],[object Object],[object Object],[object Object],[object Object]
교훈   #1:  고수준의 게임 코드에도  TDD 를 적용할 수 있다 .
예시 :  공격형 인공지능 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()); }
예시 :  캐릭터의 행동 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(&quot;TransitionState&quot;),   output.nextState->GetClassInfo().GetName()); const TransitionState& transition = *output.nextState; CHECK_EQUAL(std::string(&quot;RunningState&quot;),   transition.endState->GetClassInfo().GetName()); }
구조의 선택
교훈   #2: TDD 와 코드 설계
교훈   #3:  검사 횟수는 프로젝트 진행의 척도가 될 수 있다
교훈   #4: TDD 는 빌드의 안정성을 높여준다
교훈   #5: TDD 는 더 많은 코드를 만들어 낸다
교훈   #6:  개발 속도
교훈   #7: TDD 를   도입하기
교훈   #7: TDD  도입하기 ,[object Object],[object Object]
1.  테스트 주도 개발 (TDD) 이란 ? 2.  우리는  TDD 를 어떻게 사용했는가 3. TDD 와 게임 4.  우리가 얻은 교훈들 5.  결론
결론
질문 ? ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Noel Llopis -  [email_address]

Contenu connexe

Tendances

xUnitTestPattern/chapter7
xUnitTestPattern/chapter7xUnitTestPattern/chapter7
xUnitTestPattern/chapter7종빈 오
 
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It종빈 오
 
시작하자 단위테스트
시작하자 단위테스트시작하자 단위테스트
시작하자 단위테스트YongEun Choi
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기Heo Seungwook
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블YongEun Choi
 
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013Esun Kim
 
GCGC- CGCII 서버 엔진에 적용된 기술 (3) - Exception
GCGC- CGCII 서버 엔진에 적용된 기술 (3) - ExceptionGCGC- CGCII 서버 엔진에 적용된 기술 (3) - Exception
GCGC- CGCII 서버 엔진에 적용된 기술 (3) - Exception상현 조
 
[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개Jong Pil Won
 
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard LibraryDongMin Choi
 
인수테스트 주도 개발
인수테스트 주도 개발인수테스트 주도 개발
인수테스트 주도 개발Jaehoon Oh
 
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010Ryan Park
 
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원탑크리에듀(구로디지털단지역3번출구 2분거리)
 

Tendances (13)

xUnitTestPattern/chapter7
xUnitTestPattern/chapter7xUnitTestPattern/chapter7
xUnitTestPattern/chapter7
 
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
 
시작하자 단위테스트
시작하자 단위테스트시작하자 단위테스트
시작하자 단위테스트
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블
 
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
 
Spring statemachine
Spring statemachineSpring statemachine
Spring statemachine
 
GCGC- CGCII 서버 엔진에 적용된 기술 (3) - Exception
GCGC- CGCII 서버 엔진에 적용된 기술 (3) - ExceptionGCGC- CGCII 서버 엔진에 적용된 기술 (3) - Exception
GCGC- CGCII 서버 엔진에 적용된 기술 (3) - Exception
 
[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개
 
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library
 
인수테스트 주도 개발
인수테스트 주도 개발인수테스트 주도 개발
인수테스트 주도 개발
 
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
 
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원
스프링프레임워크 & 마이바티스 무.료 강의자료 제공 (Spring IoC & DI)_ 구로자바학원/구로오라클학원/구로IT학원
 

Similaire à Agile Test Driven Development For Games What, Why, And How

TDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDTDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDSuwon Chae
 
Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018KyungHo Jung
 
NDC11_슈퍼클래스
NDC11_슈퍼클래스NDC11_슈퍼클래스
NDC11_슈퍼클래스noerror
 
한국 커뮤니티 데이 트랙2, 세션2 JavaScript 성능향상과 Sencha
한국 커뮤니티 데이 트랙2, 세션2 JavaScript 성능향상과 Sencha한국 커뮤니티 데이 트랙2, 세션2 JavaScript 성능향상과 Sencha
한국 커뮤니티 데이 트랙2, 세션2 JavaScript 성능향상과 Senchamniktw
 
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10Ryan Park
 
어플 개발자의 서버개발 삽질기
어플 개발자의 서버개발 삽질기어플 개발자의 서버개발 삽질기
어플 개발자의 서버개발 삽질기scor7910
 
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅NAVER D2
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental systemJaehoon Oh
 
Clean code
Clean codeClean code
Clean codebbongcsu
 
TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기Wonchang Song
 
120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장tedypicker
 
자바 테스트 자동화
자바 테스트 자동화자바 테스트 자동화
자바 테스트 자동화Sungchul Park
 
[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기Sang Heon Lee
 
공유 Jdk 7-2-project coin
공유 Jdk 7-2-project coin공유 Jdk 7-2-project coin
공유 Jdk 7-2-project coinknight1128
 
NDC11_김성익_슈퍼클래스
NDC11_김성익_슈퍼클래스NDC11_김성익_슈퍼클래스
NDC11_김성익_슈퍼클래스Sungik Kim
 
불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 명신 김
 
프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가홍준 김
 
이산수학 C1 프로젝트 7
이산수학 C1 프로젝트 7이산수학 C1 프로젝트 7
이산수학 C1 프로젝트 7pkok15
 

Similaire à Agile Test Driven Development For Games What, Why, And How (20)

TDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDTDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDD
 
Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018
 
NDC11_슈퍼클래스
NDC11_슈퍼클래스NDC11_슈퍼클래스
NDC11_슈퍼클래스
 
한국 커뮤니티 데이 트랙2, 세션2 JavaScript 성능향상과 Sencha
한국 커뮤니티 데이 트랙2, 세션2 JavaScript 성능향상과 Sencha한국 커뮤니티 데이 트랙2, 세션2 JavaScript 성능향상과 Sencha
한국 커뮤니티 데이 트랙2, 세션2 JavaScript 성능향상과 Sencha
 
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
 
어플 개발자의 서버개발 삽질기
어플 개발자의 서버개발 삽질기어플 개발자의 서버개발 삽질기
어플 개발자의 서버개발 삽질기
 
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental system
 
Spring Boot 2
Spring Boot 2Spring Boot 2
Spring Boot 2
 
Clean code
Clean codeClean code
Clean code
 
TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기
 
120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장
 
자바 테스트 자동화
자바 테스트 자동화자바 테스트 자동화
자바 테스트 자동화
 
[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기
 
공유 Jdk 7-2-project coin
공유 Jdk 7-2-project coin공유 Jdk 7-2-project coin
공유 Jdk 7-2-project coin
 
NDC11_김성익_슈퍼클래스
NDC11_김성익_슈퍼클래스NDC11_김성익_슈퍼클래스
NDC11_김성익_슈퍼클래스
 
불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14
 
이산수학07
이산수학07이산수학07
이산수학07
 
프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가
 
이산수학 C1 프로젝트 7
이산수학 C1 프로젝트 7이산수학 C1 프로젝트 7
이산수학 C1 프로젝트 7
 

Plus de Ryan Park

위대한 게임개발팀의 공통점
위대한 게임개발팀의 공통점위대한 게임개발팀의 공통점
위대한 게임개발팀의 공통점Ryan Park
 
Domain Driven Design Ch7
Domain Driven Design Ch7Domain Driven Design Ch7
Domain Driven Design Ch7Ryan Park
 
즉흥연기와프로그래밍
즉흥연기와프로그래밍즉흥연기와프로그래밍
즉흥연기와프로그래밍Ryan Park
 
Oop design principle SOLID
Oop design principle SOLIDOop design principle SOLID
Oop design principle SOLIDRyan Park
 
OOP 설계 원칙 S.O.L.I.D.
OOP 설계 원칙 S.O.L.I.D.OOP 설계 원칙 S.O.L.I.D.
OOP 설계 원칙 S.O.L.I.D.Ryan Park
 
Unicode 이해하기
Unicode 이해하기Unicode 이해하기
Unicode 이해하기Ryan Park
 
Oop design principle
Oop design principleOop design principle
Oop design principleRyan Park
 
나도기술서번역한번해볼까 in NDC10
나도기술서번역한번해볼까 in NDC10나도기술서번역한번해볼까 in NDC10
나도기술서번역한번해볼까 in NDC10Ryan Park
 
나도(기술서)번역한번해볼까
나도(기술서)번역한번해볼까나도(기술서)번역한번해볼까
나도(기술서)번역한번해볼까Ryan Park
 
Programming Game AI by Example. Ch7. Raven
Programming Game AI by Example. Ch7. RavenProgramming Game AI by Example. Ch7. Raven
Programming Game AI by Example. Ch7. RavenRyan Park
 
AIbyExample - Ch7 raven. version 0.8
AIbyExample - Ch7 raven. version 0.8AIbyExample - Ch7 raven. version 0.8
AIbyExample - Ch7 raven. version 0.8Ryan Park
 
카사 공개세미나1회 W.E.L.C.
카사 공개세미나1회  W.E.L.C.카사 공개세미나1회  W.E.L.C.
카사 공개세미나1회 W.E.L.C.Ryan Park
 
온라인 게임에서 사례로 살펴보는 디버깅
온라인 게임에서 사례로 살펴보는 디버깅온라인 게임에서 사례로 살펴보는 디버깅
온라인 게임에서 사례로 살펴보는 디버깅Ryan Park
 
프로그램은 왜 실패하는가 1장
프로그램은 왜 실패하는가 1장프로그램은 왜 실패하는가 1장
프로그램은 왜 실패하는가 1장Ryan Park
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Ryan Park
 

Plus de Ryan Park (20)

위대한 게임개발팀의 공통점
위대한 게임개발팀의 공통점위대한 게임개발팀의 공통점
위대한 게임개발팀의 공통점
 
Domain Driven Design Ch7
Domain Driven Design Ch7Domain Driven Design Ch7
Domain Driven Design Ch7
 
Taocp1 2 4
Taocp1 2 4Taocp1 2 4
Taocp1 2 4
 
즉흥연기와프로그래밍
즉흥연기와프로그래밍즉흥연기와프로그래밍
즉흥연기와프로그래밍
 
Oop design principle SOLID
Oop design principle SOLIDOop design principle SOLID
Oop design principle SOLID
 
OOP 설계 원칙 S.O.L.I.D.
OOP 설계 원칙 S.O.L.I.D.OOP 설계 원칙 S.O.L.I.D.
OOP 설계 원칙 S.O.L.I.D.
 
Unicode 이해하기
Unicode 이해하기Unicode 이해하기
Unicode 이해하기
 
Unicode100
Unicode100Unicode100
Unicode100
 
Unicode
UnicodeUnicode
Unicode
 
Unicode
UnicodeUnicode
Unicode
 
Unicode
UnicodeUnicode
Unicode
 
Oop design principle
Oop design principleOop design principle
Oop design principle
 
나도기술서번역한번해볼까 in NDC10
나도기술서번역한번해볼까 in NDC10나도기술서번역한번해볼까 in NDC10
나도기술서번역한번해볼까 in NDC10
 
나도(기술서)번역한번해볼까
나도(기술서)번역한번해볼까나도(기술서)번역한번해볼까
나도(기술서)번역한번해볼까
 
Programming Game AI by Example. Ch7. Raven
Programming Game AI by Example. Ch7. RavenProgramming Game AI by Example. Ch7. Raven
Programming Game AI by Example. Ch7. Raven
 
AIbyExample - Ch7 raven. version 0.8
AIbyExample - Ch7 raven. version 0.8AIbyExample - Ch7 raven. version 0.8
AIbyExample - Ch7 raven. version 0.8
 
카사 공개세미나1회 W.E.L.C.
카사 공개세미나1회  W.E.L.C.카사 공개세미나1회  W.E.L.C.
카사 공개세미나1회 W.E.L.C.
 
온라인 게임에서 사례로 살펴보는 디버깅
온라인 게임에서 사례로 살펴보는 디버깅온라인 게임에서 사례로 살펴보는 디버깅
온라인 게임에서 사례로 살펴보는 디버깅
 
프로그램은 왜 실패하는가 1장
프로그램은 왜 실패하는가 1장프로그램은 왜 실패하는가 1장
프로그램은 왜 실패하는가 1장
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005
 

Agile Test Driven Development For Games What, Why, And How

  • 1. 게임을 위한 테스트 주도 개발 : 무엇을 , 왜 그리고 어떻게 ? Noel Llopis Senior Architect High Moon Studios 번역 : 박일 http:// ParkPD.egloos.com 도움 : 김기웅 http://betterways.tistory.com/
  • 2.
  • 3.
  • 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:k G (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; F U (Y (t + 28) + 1536) |= 62 & -n; M U (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; } }
  • 5.  
  • 6. TDD 는 앞서 언급된 문제들을 해결해주었다
  • 7.
  • 8. 장점 : 단순함과 모듈화
  • 9. 장점 : 안전망
  • 10.
  • 11.  
  • 12. 장점 : 문서화
  • 13. TDD != 단위 검사 TDD != 테스팅 전략 TDD == 개발 기법
  • 14.
  • 15. 캐릭터 + 방패 Character Damage(x) Shield Damage(x) class Character { IShield* m_shield; public: Character(); void Damage(float amount); float GetHealth() const; };
  • 16.
  • 17. 반환되는 값 검사 TEST (ShieldCanBeDamagedIfFull) { } 방패 방패 검사하기 bool Damage() 데미지 ? Shield shield; CHECK (shield.Damage()); “ ShieldLevelStartsFull 에서 오류 발생 : 100 을 예상했지만 , 0 이 나옴 . ”
  • 18. 상태 검사 TEST (LevelCannotBeDamagedBelowZero) { } 방패 방패 검사하기 Damage(200) GetLevel() Shield shield; shield.Damage(200); CHECK_EQUAL (0, shield.GetLevel()); 0?
  • 19.
  • 20.
  • 22. 상호작용 검사 ( 초기에 문제가 될 수 있다 . ) 캐릭터 검사하기 캐릭터 Damage() *m_shield TEST(CharacterUsesShieldToAbsorbDamage) { Character character(400); character.Damage(100); CHECK_EQUAL(390, character.GetHealth()); } 390? 방패 GetHealth() 화려한 방패
  • 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) 의 외부에 위치한 객체를 대신한다 .
  • 24. Mock 을 사용해서 검사하기 캐릭터 검사하기 TEST(CharacterUsesShieldToAbsorbDamage) { } 가짜 방패 MockShield mockShield = new MockShield; mockShield->damageToReturn = 10; Character character(400, mockShield); character.Damage(200); CHECK_EQUAL(200, mockShield->damagePassedIn); CHECK_EQUAL(390, character.GetHealth()); 캐릭터 Damage() *m_shield 매개 변수들은 정확한가 ? GetHealth() 반환된 데미지가 정확하게 사용되는가 ?
  • 25. 최상의 관행 : 근처의 코드만 검사하기 검사 검사중인 코드 검사 검사중인 코드 하위 시스템 A 하위 시스템 B 하위 시스템 C 고양이가 끄집어낸 어떤 것 부엌의 싱크대 누가 알겠어
  • 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(&quot;Bone1&quot;)); 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); }
  • 27. 최상의 관행 : 신속한 검사 Slow Test(24 > 20 ms): CheckSpotOverlapIsHandledCorrectly1Test Slow Test(25 > 20 ms): CheckSpotOverlapIsHandledCorrectly2Test Slow Test(24 > 20 ms): DeleteWaveEventFailsIfEventDoesntExistInCueTest Slow Test(22 > 20 ms): CanGetObjectsInBrowserListPackageTest Slow Test(48 > 20 ms): HmAddActorCallsCreateActorTest Slow Test(74 > 20 ms): HmReplaceActorDoesNothingIfEmptySelectionTest Slow Test(57 > 20 ms): HmReplaceActorWorksIfTwoActorsSelectedTest Slow Test(26 > 20 ms): ThrowExceptionWhenTrackIndexOutOfRangeTest 1923 회 검사의 총소요 시간 : 4.83 초 . 26 회의 느린 검사에 소요된 시간 : 2.54 초 .
  • 28. 최상의 관행 : 신속한 검사 Debug 상태에서 TestDebugServer 의 단위 검사 실행중 .. 검사 116 번 실행 실패한 검사 없음 . 소요 시간 : 0.016 초 . Debug 상태에서 TestStreams 의 단위 검사 실행중 ... 검사 138 번 실행 실패한 검사 없음 . 소요 시간 : 0.015 초 . Debug 상태에서 TestMath 의 단위 검사 실행중 ... 검사 245 번 실행 실패한 검사 없음 . 소요 시간 : 0.001 초 . 단위 검사 실행중 ... 검사 184 번 실행 실패한 검사 없음 . 소요 시간 : 0.359 초 .
  • 29. 최상의 관행 : 비의존적인 검사 g_CollisionWorldSingleton
  • 30.
  • 31. 콘솔의 경우 , PC 보다는 덜 자주 검사했다 .
  • 32.  
  • 33. API 전체를 감싸기 (wrap)
  • 34. API 상태를 직접 검사하기
  • 35. API 함수 호출을 제외한 모든 코드를 검사하기
  • 36. 미들웨어까지 포함해서 검사하기 Havok RenderWare Unreal Novodex OpenGL DirectX
  • 38. TDD 를 해보고는 싶지만 ...
  • 39.
  • 40. 교훈 #1: 고수준의 게임 코드에도 TDD 를 적용할 수 있다 .
  • 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()); }
  • 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(&quot;TransitionState&quot;), output.nextState->GetClassInfo().GetName()); const TransitionState& transition = *output.nextState; CHECK_EQUAL(std::string(&quot;RunningState&quot;), transition.endState->GetClassInfo().GetName()); }
  • 44. 교훈 #2: TDD 와 코드 설계
  • 45. 교훈 #3: 검사 횟수는 프로젝트 진행의 척도가 될 수 있다
  • 46. 교훈 #4: TDD 는 빌드의 안정성을 높여준다
  • 47. 교훈 #5: TDD 는 더 많은 코드를 만들어 낸다
  • 48. 교훈 #6: 개발 속도
  • 49. 교훈 #7: TDD 를 도입하기
  • 50.
  • 51. 1. 테스트 주도 개발 (TDD) 이란 ? 2. 우리는 TDD 를 어떻게 사용했는가 3. TDD 와 게임 4. 우리가 얻은 교훈들 5. 결론
  • 53.