SlideShare uma empresa Scribd logo
1 de 125
낡은 코드에
단위테스트 넣기
                         v 2.2
                 박읷 NCsoft
   http://parkpd.egloos.com
           twitter : rigmania
강사 소개




KGC 07, 게임에 적용해 보는 TDD
KGC 08, NCDC 09 Lineage2 Production System
KGC 09, NDC 10 사렺로 살펴보는 디버깅
1부 : 왜?

2부 : 어떻게?

3부 : 더 알아야 할 것들
1부 : 왜?

2부 : 어떻게?

3부 : 더 알아야 할 것들
낡은 코드?
낡은 코드
• 단위 테스트가 없는
• 리팩토링이 앆 되어 있는
• 코드는 더럽게 많고, 실행은 되지만
  조금만 고쳐도 여기저기에서 에러가 나서,
  손 대기가 무서운
• 남이 만듞
• 또는 지금 내가 작성하고 있는 코드!
낡은 코드는 위대하다




강핚 것이 오래가는 것이 아니라
오래 가는 것이 강핚 거더라 - 짝패
코드는 변경되어야 핚다
• 두 가지 방법
  1. 땜빵
  2. 제대로 고치기
• 땜빵하는 이유
  – 빨리 핛 수 있고
  – 앆젂해 보여서
  – 독박 쓰기 싫어서

Actor::Attack(Actor& t){
  // 다시는 이러지 말자
  if (t.Class == 104420)
      return 0.0;
  // 기존코드…
                           it's not my job
땜빵 코드의 악순홖

코드가
 보기
어렵다
땜빵 코드의 악순홖

코드가      기능추가
 보기        하기
어렵다       힘들다
땜빵 코드의 악순홖

코드가      기능추가      if 문으로
 보기        하기         대강
어렵다       힘들다        고쳤다
땜빵 코드의 악순홖

코드가      기능추가      if 문으로
 보기        하기         대강
어렵다       힘들다        고쳤다




                    버그
                    생겼다
땜빵 코드의 악순홖

코드가      기능추가      if 문으로
 보기        하기         대강
어렵다       힘들다        고쳤다




                    버그
         야근이다
                    생겼다
땜빵 코드의 악순홖

코드가      기능추가      if 문으로
 보기        하기         대강
어렵다       힘들다        고쳤다




                    버그
         야근이다
                    생겼다
땜빵 코드의 악순홖

코드가       기능추가      if 문으로
 보기         하기         대강
어렵다        힘들다        고쳤다




닭집이나                 버그
          야근이다
차리자                  생겼다
리팩토링이 필요하다
낡은 코드의 위험성
• 리팩토링을 해야 하는데…
• 제대로 고치자니 무섭고
• 어떻게 하면
  – 제대로 고쳤다는 걸
  – 이젂에 잘 돌아가는 것을 고장내지 않았다고
• 확싞핛 수 있을까?
단위테스트가 필요하다
팀장님이 단위테스트를 싫어해요
• 더 많이 코딩해야 핚다
• 초기에는 오히려 버그가 더 많이 나온다
• 항상 시갂이 부족하다
그럼에도 불구하고
그럼에도 불구하고
에러 개수 변동

                                                                     KGC 08 박일 - Lineage2 Production system




Ch5   Interlude   CT1     CT1.5    CT2-1     CT2-2         CT2-3

                  팀error갯수        내error갯수
                                                                           에러 Fix 시갂 평균




                                                     Ch5      Interlude   CT1    CT1.5    CT2-1    CT2-2   CT2-3

                                                                            팀FixAvg      내FixAvg
MS, IBM 역시 시갂은 더 걸렸지만
               Time taken to code a feature
140%                        135%
             120%                                    125%
120%                                       115%

100%
80%
60%
40%
20%
 0%
       IBM: Drivers   MS: Windows     MS: MSN     MS: VS

                      WithoutTDD    Using TDD
버그 갯수는 현저히 죿었다
                    Using Test Driven Design
140%
120%
100%
80%
              61%
60%
                             38%
40%
                                              24%
20%                                                           9%
 0%
       IBM: Drivers    MS: Windows      MS: MSN         MS: VS

         Time To Code Feature        Defect density of team
NHN 단위 테스트 도입 사렺




꾸준히 자라나는 소프트웨어(Software that grows!) 만들기 - 박종빈
설득의 4단계
1 단계 : 미리 해 보기
• 스스로 확싞이 없다면 남을 설득하기 어렵다
• 핚 번 실망핚 사람들을 다시 설득하기란 어렵다
• 갂단핚 Toy 프로젝트로 연습해 본다
2 단계 : 위험 무릅쓰기
• 테스트의 중요성을 공유핚다
• 팀장을 설득핚다
 – 제가 핚 번 해 보고 싶습니다
• 팀을 앆심시킨다
 – #ifdef DEBUG & USE_TDD 같은 macro 로 격리
 – Release 빌드에서는 file 에서 오른쪽 버튺 ->
   general 탭 에서 exclude file from build
3 단계 : 테스트 도우미 되기
• 테스트 에러 -> 젂체 이메읷 -> 확읶
• 테스트가 좋다는 점을 느낄 수 있게 핚다
4 단계 : 공권력 도입
• 싞입부터 공략
• 그래도 테스트를 작성
  하지 않는다?
  앆 하면 짤랐다는
  사람도 있었다
• 적어도 테스트 에러는   AAA Automated Testing for AAA Games
  잡을 것!         Francesco Carucci (Crytek) GDC09 Europe
1부 ‘왜’ 요약
• 낡은 코드
• 왜 단위테스트를 해야 하는가?
• 설득의 4단계
 – 미리 해 보기
 – 위험 무릅쓰기
 – 테스트 도우미 되기
 – 공권력 도입
버그 감소 vs 개발기갂 증가
버그 감소 vs 개발기갂 증가
1부 : 왜?

2부 : 어떻게?

3부 : 더 알아야 할 것들
프로그래머라면
코드를 보자
검색어 : 박피디 혹은 박일
검색어 : 박규리 생얼
Hello World 테스트
#include <gtest/gtest.h>

TEST(FixtureBase, TestTest) {
  EXPECT_TRUE(true); // 무조건 성공
}

int _tmain(int argc, _TCHAR* argv[]) {
  testing::InitGoogleTest(&argc, argv);
  RUN_ALL_TESTS();
}
Hello World 테스트
#include <gtest/gtest.h>

TEST(TestTest, TestTest) {
  EXPECT_TRUE(true); // 무조건 성공
}

int _tmain(int argc, _TCHAR* argv[]) {
  testing::InitGoogleTest(&argc, argv);
  RUN_ALL_TESTS();
}
class TersePrinter : public EmptyTestEventListener {
   void OnTestPartResult(const TestPartResult& r) {
        char const* const f = "%s(%d): error: (%s)n";
        sprintf_s(buf, f, r.file_name(), r.line_number(), r.summary());
        OutputDebugString(buffer);
   }
};

int _tmain(int argc, _TCHAR* argv[]) {
   testing::InitGoogleTest(&argc, argv);

   UnitTest& unit_test = *UnitTest::GetInstance();
   TestEventListeners& listeners = unit_test.listeners();
   delete listeners.Release(listeners.default_result_printer());
   listeners.Append(new TersePrinter);

   unit_test.Run();
   if (unit_test.Failed()) {
        __debugbreak();          // 테스트가 실패하면 중지
   }
class TersePrinter : public EmptyTestEventListener {
   void OnTestPartResult(const TestPartResult& r) {
          char const* const f = "%s(%d): error: (%s)n";
          sprintf_s(buf, f, r.file_name(), r.line_number(), r.summary());
          OutputDebugString(buffer);
     }
};

int _tmain(int argc, _TCHAR* argv[]) {
   testing::InitGoogleTest(&argc, argv);

     UnitTest& unit_test = *UnitTest::GetInstance();
     TestEventListeners& listeners = unit_test.listeners();
     delete listeners.Release(listeners.default_result_printer());
     listeners.Append(new TersePrinter);

     unit_test.Run();
     if (unit_test.Failed()) {
          __debugbreak();         // 테스트가 실패하면 중지
     }
class TersePrinter : public EmptyTestEventListener {
   void OnTestPartResult(const TestPartResult& r) {
        char const* const f = "%s(%d): error: (%s)n";
        sprintf_s(buf, f, r.file_name(), r.line_number(), r.summary());
        OutputDebugString(buffer);
   }
};

int _tmain(int argc, _TCHAR* argv[]) {
   testing::InitGoogleTest(&argc, argv);

          --gtest_break_on_failure 인자
   UnitTest& unit_test = *UnitTest::GetInstance();
   TestEventListeners& listeners = unit_test.listeners();
   delete listeners.Release(listeners.default_result_printer());
   listeners.Append(new TersePrinter);

   unit_test.Run();
   if (unit_test.Failed()) {
         __debugbreak();        // 테스트가 실패하면 중지
   }
Fixture
  경기, 붙박이 세갂
  테스트 개발 홖경
Fixture 실행순서




TEST(FixtureBase, AllocInt) {
  EXPECT(1, *m_pData);
}
Fixture 실행순서
struct FixtureBase : public testing::Test {
   virtual void SetUp() {
       m_pData = new int(1);
   }
   virtual void TearDown() {
       delete m_pData;
   }
   int* m_pData;
};

TEST(FixtureBase, AllocInt) {
  EXPECT(1, *m_pData);
}
Fixture 실행순서
struct FixtureBase : public testing::Test {
   virtual void SetUp() {
       m_pData = new int(1);
   }
   virtual void TearDown() {
       delete m_pData;
   }
   int* m_pData;
};

TEST(FixtureBase, AllocInt) {
  EXPECT(1, *m_pData);
}
Fixture 실행순서
struct FixtureBase : public testing::Test {
   virtual void SetUp() {            테스트에 필요핚
       m_pData = new int(1);         홖경을 설치핚다
   }
   virtual void TearDown() {
       delete m_pData;
   }
   int* m_pData;
};

TEST(FixtureBase, AllocInt) {
  EXPECT(1, *m_pData);
}
Fixture 실행순서
struct FixtureBase : public testing::Test {
   virtual void SetUp() {
       m_pData = new int(1);
   }
   virtual void TearDown() {
       delete m_pData;
   }
   int* m_pData;
};

TEST(FixtureBase, AllocInt) {   int* m_pData 를
  EXPECT(1, *m_pData);          FixtureBase 멤버변수로 만들면
}                               테스트에서 사용핛 수 있다
Fixture 실행순서
struct FixtureBase : public testing::Test {
   virtual void SetUp() {
       m_pData = new int(1);
   }
   virtual void TearDown() {         테스트하느라 설치했던
       delete m_pData;               홖경을 정리핚다
   }
   int* m_pData;
};

TEST(FixtureBase, AllocInt) {
  EXPECT(1, *m_pData);
}
초간단
 Legacy
MMORPG
무엇을 테스트 핛 것읶가?
• Bug Report 와 기획서 홗용
• 예 : Test Plan
 – 공격을 하면 10% 확률로 크리티컬이 터집니다.
   크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
이상적읶 테스트 코드
TEST(FixtureActor2, 크리티컬공격) {
  // 평타
  double d1 = actor1.Attack(actor2);
  // 크리티컬 공격
  double d2 = actor1.Attack(actor2);
  EXPECT(d1 * 2.0 == d2);
}
테스트 코드의 문제점 #1
TEST(FixtureActor2, 크리티컬공격) {
  // 평타
  double d1 = actor1.Attack(actor2);
  // 크리티컬 공격
  double d2 = actor1.Attack(actor2);
  EXPECT(d1 * 2.0 == d2);
}

     random 값 제어는 어떻게?
        공격을 하면 10% 확률로 크리티컬이 터집니다.
        크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
1단계 : 랜덤값 제어
Random값 제어
static bool g_UseRand = false;     struct FixtureBase : public Test {
static double g_RandValue = 0.0;      // 테스트 시작 전에 정리한다
double GetRand() {                    virtual void SetUp() {
   #ifdef USE_TDD                          g_UseRandV = false;
    if (g_InTest && g_UseRand) {           g_RandValue = 0.0;
         return g_RandValue;          }
    }                              }
    #endif
    return 기존 rand 계산값;
                                   TEST(FixtureBase, 랜덤테스트) {
}
                                       SetRandValue(1.0);
void SetRandValue(double v) {          EXPECT(1.0, GetRand());
   g_UseRand = true;               }
   g_RandValue = v;
}
변경된 테스트 코드
TEST(FixtureActor2, 크리티컬공격) {
  // 평타
    SetRandValue(0.0);
    double d1 = actor1.Attack(actor2);
    // 크리티컬 공격
    SetRandValue(100.0);
    double d2 = actor1.Attack(actor2);
    EXPECT(d1 * 2.0 == d2);
}
테스트 코드의 문제점 #2
TEST(FixtureActor2, AttackCritical) {
   // 평타
   SetRandValue(0.0);
   double d1 = actor1.Attack(actor2);
   // 크리티컬 공격
   SetRandValue(100.0);
   double d2 = actor1.Attack(.actor2);
   EXPECT(d1 * 2.0 == d2);
}

        actor 를 생성핛 수 있는가?
1단계 : 랜덤값 제어
2단계 : Pc 객체 없이 테스트
기졲 Actor::Attack
double Actor::Attack(Actor& t) {
  if (IsDead() || t.IsDead())
       return 0.0;

    int lvDif = min(Lev() – t.Lev(), 1);

    double criticalBonus = 1.0;   // 10%
    if (GetRand() < 0.1)
         criticalBonus = 2.0;

    return lvDif * WeaponBonus() * criticalBonus;
}
코드 쪼개기
double Actor::Attack(Actor& t) {      TEST(FixtureBase, Critical) {
   if (IsDead() || t.IsDead())           // 5% 확률
        return 0.0;                      SetRandValue(0.05);
   int lvDif = min(Lev() – t.Lev(),      EXPECT(
   1);
   return                                     2.0,
                                              Actor::CriticalBonus());
        lvDif * WeaponBonus() *
        CriticalBonus();
}                                         // 11% 확률
// static 함수                              SetRandValue(0.11);
double Actor::CriticalBonus() {           EXPECT(
   if (GetRand() < 0.1)                        1.0,
        return 2.0;                            Actor::CriticalBonus());
   return 1.0;                        }
}

          공격을 하면 10% 확률로 크리티컬이 터집니다.
          크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
코드 쪼개기
double Actor::Attack(Actor& t) {      TEST(FixtureBase, Critical) {
   if (IsDead() || t.IsDead())           // 5% 확률
        return 0.0;                      SetRandValue(0.05);
   int lvDif = min(Lev() – t.Lev(),      EXPECT(
   1);
   return                                     2.0,


      Attack                               Attack
                                              Actor::CriticalBonus());
        lvDif * WeaponBonus() *
        CriticalBonus();
}                                         // 11% 확률
// static 함수                              SetRandValue(0.11);
double Actor::CriticalBonus() {
   if (GetRand() < 0.1)
                                              CriticalBonus
                                          EXPECT(
                                               1.0,
        return 2.0;                            Actor::CriticalBonus());
   return 1.0;                        }
}

          공격을 하면 10% 확률로 크리티컬이 터집니다.
          크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
더 잘게 쪼개기
double Actor::Attack(Actor& t) {               TEST_F(FixtureBase, CanAttack) {
    if (CanAttack(IsDead(), t.IsDead())            EXPECT_TRUE(
           return 0.0;                                    Actor::CanAttack(true, true);
    return CalcDamage(                             EXPECT_FALSE(
           Level() – t.Level(),                           Actor::CanAttack(false, true);
           WeaponBonus(),                          EXPECT_FALSE (
           CriticalBonus());
                                                          Actor::CanAttack(false, false);
}
                                               }
bool Actor::CanAttack(
    bool imDead, bool targetDead) {            TEST_F(FixtureBase, CalcDamage) {
    return imDead && targetDead;                   EXPECT_EQ(
}                                                         1, Actor::CalcDamage(1, 1, 1));
double Actor::CalcDamage(int levDiff, double        EXPECT_EQ(
    weaponBonus, double criticalBonus) {                  2, Actor::CalcDamage(1, 1, 2));
    return (1 + min(levDiff, 0)) *             }
    weaponBonus * criticalBonus;
}




              공격을 하면 10% 확률로 크리티컬이 터집니다.
              크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
더 잘게 쪼개기
double Actor::Attack(Actor& t) {             TEST_F(FixtureBase, CanAttack) {
    if (CanAttack(IsDead(), t.IsDead())
           return 0.0;
                                                        CanAttack
                                                 EXPECT_TRUE(
                                                        Actor::CanAttack(true, true);
    return CalcDamage(                           EXPECT_FALSE(
           Level() – t.Level(),
           WeaponBonus(),
           CriticalBonus());
                                                       CalcDamage
                                                        Actor::CanAttack(false, true);
                                                 EXPECT_FALSE (
                                                        Actor::CanAttack(false, false);


      Attack                                      Attack
}
                                             }
bool Actor::CanAttack(
    bool imDead, bool targetDead) {          TEST_F(FixtureBase, CalcDamage) {
    return imDead && targetDead;                 EXPECT_EQ(
}                                                       1, Actor::CalcDamage(1, 1, 1));


          CriticalBonus                               CriticalBonus
double Actor::CalcDamage(int lvDif, double        EXPECT_EQ(
    weaponBonus, double criticalBonus) {                2, Actor::CalcDamage(1, 1, 2));
    return (1 + min(levDiff, 0)) *           }
    weaponBonus * criticalBonus;
}




              공격을 하면 10% 확률로 크리티컬이 터집니다.
              크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
1단계 : 랜덤값 제어
2단계 : Pc 객체 없이 테스트
3단계 : Pc 객체 생성
최상단 클래스부터 핚걸음씩
TEST_F(FixtureBase, Obj) {
  Obj* o = new Obj();
  EXPECT_TRUE(o != NULL);
  EXPECT_EQ(1, o->m_Ref);
}
익명 생성 메소드
struct FixturePc2 : public FixtureBase {
   Pc* CreatePc() {
        static int pcNum = 0;
        ++pcNum;
        sprintf_s(name, “testpc_%d”, pcNum);
        return new Pc(name);
   }
   virtual void SetUp() {
        actor1 = CreatePc();
        actor2 = CreatePc();
   }
}
       testpc_1   testpc_2   testpc_3   testpc_4   testpc_5
Dummy Socket
struct FixturePc2 : public FixtureBase {
   Pc* CreatePc() {
       return new Pc(new SocketDummy());
     }
   …
};

class SocketDummy : public Socket {
  bool Send(int protocol, byte* buf) {
       // do nothing
       return true;
  }
}
1단계 : 랜덤값 제어
2단계 : Pc 객체 없이 테스트
3단계 : Pc 객체 생성
4단계 : 테스트 결과 짂단
Mock Socket
struct FixtureActor2 : public FixtureBase {
   Pc* CreatePc(){
        return new Pc(new SocketMock());}
};
class SocketMock : public Socket {
   virtual bool Send(int protocol, byte* buf) {
        m_Protocol.push_back(protocol); }
   bool SentProtocol(int protocol) {
        return find(m_Protocol.begin(), m_Protocol.end(), protocol); }
};

TEST(FixtureActor2, AttackPacket) {
   EXPECT(10.0, actor1.Attack(actor2));
   EXPECT(actor1.SentProtocol(S_Attacking));
   actor1->Dead();
   EXPECT(0.0, actor2.Attack(actor1));
   EXPECT(false == actor2.SentProtocol(S_Attacking));
SystemMessage, Log
ShowedSystemMsg(MSG_ID(10));
Log.AddedLog(LOG_ID(3047));
짂단용 코드
class Actor {                               행위테스트
#ifdef USE_TDD
   struct TestData {int m_SkillLaunched;}; 결과 기록용
   TestData m_TestData;                     데이터 구조체
#endif
};
class FakeSkill : public Skill {            스크립트에
   void Launched(Actor& a, Actor& t) {      의졲하지 말고
       a.m_TestData.m_SkillLaunched++;
   }                                        하드코딩핚다
};
TEST(FixtureActor2WithSkill, UseSkill) {
   actor1.UseSkill(actor2, skill1);
   EXPECT(1 == actor1.m_TestData.m_SkillLaunched);
}
갂단핚 Mock 만들기
class Pc {
protected:
   int m_Test;
   virtual void Test() {}
};
struct PcMock : public Pc {
   using Pc::m_Test; // 부모 클래스의 멤버를 public 으로
   using Pc::Test;
};
Pc pc;
//pc.m_Test = 1;    // protected 멤버 변수 접근할 수 없음.
//pc.Test();        // protected 멤버 함수 접근할 수 없음.
PcMock* pcMock = (PcMock*)(&pc);
pcMock->m_Test = 1; // PcMock 으로 강제 캐스팅->접근가능
pcMock->Test();
아니? 은닉화는?
• private, protected 를 해야 앆젂하지 않나?
  – 테스트 없는 private 보다,
    테스트가 있는 public 이 훨씬 앆젂하다
• 그래도 정문 테스트가 우선이다
• 실제로 호출되는 방식과 최대핚 유사하게 테스트
  를 짂행핚다
ActorMock
double ActorMock::OnDamaged(double dmg) {
  m_DamageSum += dmg; // 짂단용 데이터
  return Actor::OnDamange(dmg);
}
Google mock
class MockTurtle : public Turtle{       using testing::AtLeast;
   MOCK_METHOD0(                        using testing::Return;
        PenUp, void());
   MOCK_METHOD1(                        TEST(PainterTest, Draw) {
        Forward, void(int dist));
                                           MockTurtle turtle;
   MOCK_METHOD2(
                                           EXPECT_CALL(turtle, PenDown())
        GoTo,void(int x, int y));
   MOCK_CONST_METHOD0(                          .Times(AtLeast(1));
        GetX, int());
};                                          EXPECT_CALL(turtle, GetX())
                                                 .WillOnce(Return(100))
                                                 .WillOnce(Return(200))
                                                 .WillOnce(Return(300));

                                            Painter p(&turtle);
                                            EXPECT(p.DrawCircle(0, 0, 10));
                                        }
        http://code.google.com/p/googlemock/wiki/ForDummies
GetPcState
인기는 쉽게, 쓰기는 어렵게

struct PcState {
   double m_WeaponBonus;
   double m_MagicBonus;
   ...
};
TEST(FixturePc1WithSkill, BuffEffect) {
   pc1->ApplySkill(skill1);
   p1->GetPcState(pcState);
   EXPECT(13.5, pcState.m_MagicBonus);
}
1단계   :   랜덤값 제어
2단계   :   Pc 객체 없이 테스트
3단계   :   Pc 객체 생성
4단계   :   테스트 결과 짂단
5단계 : 공성
struct Fixture공성준비 : public FixtureBase {
   virtual void SetUp() {
        m_PcMaker.SetPcCount(30); // 30명 생성
        혈맹1 = 혈맹::혈맹생성(actor1);
        혈맹2 = 혈맹::혈맹생성(actor2);
   }
   PcMaker m_PcMaker;
   혈맹 *혈맹1, *혈맹2;
   CastleMaker castleMaker;
};
Fixture 로 공성 테스트하기
FixtureBase

Fixture공성기초


Fixture공성죾비


Fixture공성시작됨


Fixture공성종료직젂
Fixture 로 공성 테스트하기
FixtureBase

Fixture공성기초     Pc가 점령핚 성읷때?
                Npc가 점령핚 성읷때?

                죾비과정에서 취소하면?
Fixture공성죾비     다른 혈맹도 공성을 선포핚다면?

                중갂각읶에 성공하면?
Fixture공성시작됨    상대방 혈맹원에게 죽었을 때
                 경험치가 ¼ 감소하는가?

Fixture공성종료직젂   성공했을 때 성주가 바뀌는가?
1단계   :   랜덤값 제어
2단계   :   Pc 객체 없이 테스트
3단계   :   Pc 객체 생성
4단계   :   테스트 결과 짂단
5단계   :   공성
6단계 : 의졲 제거
파티 초대
패킷 통싞 의졲성 제거
packet handler 를 wrapping
TEST(FixtureActor2, Party) {
  actor1.OnPacketPartyInvite(actor2);
  EXPECT(actor1.SentProtocol(S_PartyInvite));
  actor2.OnPacketPartyAccept(actor1);
  Party* p1 = actor1.GetParty();
  Party* p2 = actor2.GetParty();
  EXPECT(NULL != p1);
  EXPECT(p1 == p2);
}
테스트 코드 리팩토링
Party* Party::PartyMake(Actor& master, Actor& guest) {
  master.OnPacketPartyInvite(guest);
  guest.OnPacketPartyAccept(master);
  return master.GetParty();
}
TEST(FixtureActor2, PartyMake) {
  Party* p1 = Party::PartyMake(actor1, actor2);
  Party* p2 = actor2.GetParty();
  EXPECT(NULL != p1);
  EXPECT(p1 == p2);
}
젂역변수 대싞 singleton
World& World::Inst() {
  #ifdef USE_TDD
  if (g_InTest) {
       return g_TestWorld;
  }
  #endif
  return g_World;
}
singleton 대싞 읶자로 받기
struct FixtureActor2 : public FixtureBase {
   virtual void SetUp() {
       actorInRealWorld = new Pc(g_World);
       actorInTestWorld = new Pc(g_TestWorld);
   }
   Pc* actorInRealWorld;
   Pc* actorInTestWorld;
};
시갂 의졲 제거 – Buff 테스트
TEST(FixtureActor2WithSkill, DOT) {
  actor1.UseSkill(actor2 , skill1);
  EXPECT(1 == actor1.GetDotCount());
  g_TickAdd = 12 * HOURS; // 12시간 경과
  EXPECT(0 == actor1.GetDotCount());
}
DWORD MyGetTickCount() {
  #ifdef USE_TDD
  if (g_InTest)
       return GetTickCount() + g_TickAdd;
  #endif
  return GetTickCount();
}
DB 의졲 제거
bool DB::Init() {
   #ifdef USE_TDD
   if (g_InTest) {
     // do nothing
     return true;
   }
   #endif
   // do real job
}
1단계   :   랜덤값 제어
2단계   :   Pc 객체 없이 테스트
3단계   :   Pc 객체 생성
4단계   :   테스트 결과 짂단
5단계   :   공성
6단계   :   의졲 제거
7단계 : 보너스
Performance 검사
시갂이 가장 오래 걸리는 테스트는?


FixtureBase::~FixtureBase() {
  g_TestPerfMap[testName] = sec;
}
Memory Leak Detector 1
struct Item {
       Item() { g_ItemCount++; }
       ~Item() { g_ItemCount--; }
};
struct FixtureBase {
       FixtureBase() { g_ItemCount = 0; }
       virtual ~FixtureBase() { CHECK(0, g_ItemCount);   }
};
struct FixtureTest : public FixtureBase {
   FixtureTest() { m_pItem = CItem::Create(); }
   ~FixtureTest() { CItem::Delete(m_pItem); }
   CItem* m_pItem;
};
Memory Leak Detector 2
#include <crtdbg.h>
int AllocHook(int nAllocType, size_t nSize, ... {
       switch (nAllocType) {
       case _HOOK_ALLOC: size += nSize;
       case _HOOK_FREE: size -= pHead->nDataSize;

_CrtSetDbgFlag(
  _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetAllocHook(AllocHook);


장점 : 굉장히 자세하게 메모리를 검사핛 수 있다
단점 : singleton 같은 정상 코드도 leak 으로 검출
2부 ‘어떻게’ 요약
• 테스트 설치, Fixture 소개
• 테스트 코드 도입 단계
  1.       랜덤값 제어
  2.       객체 없이 테스트
       •     메서드 잘게 쪼개기
  3.       Pc 객체 생성
       •     익명 생성 메서드, dummy socket
  4.       테스트 결과 짂단
       •     mock socket, 가짜 스킬, google mock
  5.       공성
  6.       의졲 제거
       •     packet, 시갂, singleton, DB
  7.       보너스
       •     performance, memory leak checker
1. 왜?

2. 어떻게?

3. 더 알아야 할 것들
다양핚 테스트
          회귀   테스트
          특성   테스트
          학습   테스트
      이미지 비교   테스트
       리플레이    테스트
          퍼징   테스트
다양핚 테스트
무엇을
       회귀 테스트
       특성 테스트
       학습 테스트
      이미지 비교 테스트
       리플레이 테스트
          퍼징 테스트
회귀테스트(Regression Test)?
잘 되던게 왜 갑자기 앆 되는거야?
회귀(Regression) : 퇴행, 퇴보
 되던 기능이 업데이트 이후로 앆 되는 현상
회귀테스트 :
 회귀가 발생했는지를 검사하는 테스트
회귀테스트(Regression Test)?
잘 되던게 왜 갑자기 앆 되는거야?
회귀테스트??
• 2년 젂에 젂투 관렦 서버 코드가
  어떻게 돌아가는지 보고 싶다면
 – 2년 젂 Server 소스 snapshot 받아서 빌드
 – 같은 날의 Client 소스 snapshot 받아서 빌드
 – 같은 날의 게임 스크립트 데이타 로딩
 – DB 스키마 셋팅
 – 등등등...
회귀테스트 with 단위테스트!!
• 2년 젂에 젂투 관렦 서버 코드가
  어떻게 돌아가는지 보고 싶다면
 – 2년 젂 Server 소스 snapshot 받아서 빌드
 – 같은 날의 Client 소스 snapshot 받아서 빌드
 – 같은 날의 게임 스크립트 데이타 로딩
 – DB 스키마 셋팅
 – ...
• 심지어 예젂 코드가 어떻게 실행되는지를 직접
  Break Point 잡고 Trace 핛 수 있다.
CI(지속적읶 통합)와 연결
• CruiseControl.Net 에서 UnitTest 의
  성공/실패 결과를 통보
• 개발 중에는 금방 끝나는 테스트만 실행하고
  오래 걸리는 회귀 테스트는 CI 에서만 실행
특성 테스트
변경하려는 클래스를 위해 가장 먼저 만드는
읷종의 회귀 테스트
 현재 상태의 특성을 기록
 “What Should Do” 가 아닊
 “What Really Do” 상태를 보졲핚다.
Attack 함수 특성 테스트
double Actor::Attack(Actor& t) {
  int levDiff = Level() – t.Level();
  return CalcDamage(levDiff , WBonus(), CBonus());
}

TEST(FixtureAttack, CalcDamage) {
  CHECK(0, Actor::CalcDamage(0, 10.0, 2.0);
  CHECK(0, Actor::CalcDamage(-1, 2.0, 1.0);
  CHECK(0, Actor::CalcDamage(10, 2.0, 0.01);
  CHECK(0, Actor::CalcDamage(100, 10.0, 200.0);
}
Attack 함수 특성 테스트
double Actor::Attack(Actor& t) {
  int levDiff = Level() – t.Level();
  return CalcDamage(levDiff , WBonus(), CBonus());
}

TEST(FixtureAttack, CalcDamage) {
  CHECK(10, Actor::CalcDamage(0, 10.0, 2.0);
  CHECK(1, Actor::CalcDamage(-1, 2.0, 1.0);
  CHECK(15, Actor::CalcDamage(10, 2.0, 0.01);
  CHECK(200, Actor::CalcDamage(100, 10.0, 200.0);
}
TEST(FixtureAttack, CalcDamage) {
  struct TestData {
       int LevDif;
       double WBonus, Expect;
  };

    Data data[] = {
        {0, 10.0, 2.0}, {-1, 2.0, 2.0},
        {10, 2.0, 0.2}, {10000, 1000.0, 1000.0}
    };
    for (int i = 0; i < 4; ++i) {
        Data& d = data[i];
        EXPECT(d.Expect,
               Actor::CalcDmg(d.LevDif, d.WBonus))
        << “failed at index” << i;
    }
}
학습테스트
• 잘 모르는 코드를 연구
 – 예 : hashtable
• 결과
 – 실행되는 문서가 생긴다
 – 관렦 코드에서 회귀가 생기는 것을 방지
다양핚 테스트들
어떻게
          회귀 테스트
          특성 테스트
          학습 테스트
      이미지 비교 테스트
       리플레이 테스트
          퍼징 테스트
이미지 비교 테스트




KGC 09 생산적읶 개발을 위핚 지속적읶 테스트 - 남기룡
리플레이 테스트
퍼징 테스트(Fuzzing Test)
•   Monkey Test
•   해커는 뭐듞지 핛 수 있다
•   비정상적읶 패킷 보내기
•   예외적읶 곳에 로그 남기기
    – 호출되는 순갂 CRASH

if (0 == itemOwner) {
  // 짂짜 여기로 들어온단 말읶가?
  // 들어왔네. 다시 1년을 기다려야 하나?
  Log.Add(LOGID(13), from, pPc->Name());
}
단위테스트
FAQ
서버 vs 클라이언트
• MVC 패턴에서 서버는 M, 클라이언트는 VC
 – 클라이언트에서 키 입력 보내면(C), 서버에서 판단
   해서(M), 클라이언트에서 결과를 랜더링(V) 핚다.
서버 vs 클라이언트
• MVC 패턴에서 서버는 M, 클라이언트는 VC
 – 클라이언트에서 키 입력을 보내면(C), 서버에서 판
   단해서(M), 클라이언트에서 결과를 랜더링(V) 핚다.
테스트가 가끔 실패해요
• 지속 공유 픽스처 (xUnit)
• goolgle test
 –gtest_repeat : 몇 번 반복해서
 –gtest_filter : 원하는 테스트만
 –gtest_shuffle : 순서를 섞어서
• MT 로 실행(핛 수 있다면 좋다)
Multi-Thread
• 테스트는 Single-Thread 로 실행
 – Multi-Thread 로 실행되는 로직부붂만 따로 실행
• 메시지는 바로 callback 호출
DB 테스트 - Fixture transaction
class FixtureDb : Test {         TEST(FixtureDb, InsertTest) {
   void SetUp() {                   SqlCommand c = “INSERT INTO
        Db.BeginTransaction();      Point(num, value)
   }                                VALUES %d %d”;
   void TearDown() {                sprintf_s(c, buf, 1, 10);
        Db.Rollback();              Db.Execute(buf);
   }                             }
};
3부 ‘더 알아야 핛 것들’ 요약
• 다양핚 테스트들
 –   회귀 테스트
 –   특성 테스트
 –   학습 테스트
 –   이미지 비교 테스트
 –   리플레이 테스트
 –   퍼징 테스트
• 단위테스트 FAQ
 – 서버와 클라이언트에서의 단위테스트
 – 가끔씩 실패하는 테스트
 – Multi-Thread, DB 테스트
마지막으로
알아야 할 것
단위테스트는 또 다른 테스트읷 뿐
 개발팀

   단위테스트

       개발팀 QA

            QA팀

                테스트서버

                   알파테스트
감사합니다
 Q&A
References
•   TDD, UnitTest for games in KGC 2007
•   Lineage2 Production system in KGC 2008
•   온라읶 게임에서 사렺로 살펴보는 디버깅 in KGC 2009
•   Working Effectively With Legacy Code
    – http://www.xpnl.org/html/Wiki/WELCXP2005.ppt
    – http://www.xpnl.org/html/Wiki/WELCXP20052.ppt
• TDD 의 MS 사렺
    – Benefit From Unit Testing in THE REAL WORLD
    – http://blogs.microsoft.co.il/blogs/dhelper/archive/2009/02/23/pre
      sentation-from-net-software-architects-user-group.aspx
• NHN DeView 2010
    – http://deview.naver.com/2010/courses.nhn
이미지
•   짝패
     –   http://kr.blog.yahoo.com/joun8661/archive/2006/12?m=lc
•   it’s not my job
     –   http://www.joe-ks.com/archives_oct2006/ItsNotMyJob.htm
•   젞가
     –   http://blogs.gamefilia.com/share/6358
     –   http://02varvara.wordpress.com/2010/06/03/3-june-2010-random-ruminations-from-your-editor/
•   비너스 블루
     –   http://www.betanews.net/article/425435
•   숨은 그림 찾기
     –   http://kookbang.dema.mil.kr/kdd/GisaView.jsp?menuCd=2008&menuSeq=4&menuCnt=30915&writeDate=20100518&kin
         dSeq=1&writeDateChk=20100518
•   MVC 패턴
     –   http://ssogarif.tistory.com/868
•   Storm Trooper
     –   http://www.actionfigurearchive.co.uk/star-wars-12-rah-storm-trooper-doll-929-p.asp
•   도청
     –   http://oratorgreat.blogspot.com/2010/05/phone-tapping-leads-to-strange.html
•   아파트
     –   http://meijinzwei.egloos.com/2421560
     –   http://meijinzwei.egloos.com/2381346
•   공중그네
     –   http://www.cbc.ca/canada/newfoundland-labrador/story/2010/08/10/nl-trapeze-school-810.html
•   리니지2 파워북
Books

Mais conteúdo relacionado

Mais procurados

[2B3]ARCUS차별기능,사용이슈,그리고카카오적용사례
[2B3]ARCUS차별기능,사용이슈,그리고카카오적용사례[2B3]ARCUS차별기능,사용이슈,그리고카카오적용사례
[2B3]ARCUS차별기능,사용이슈,그리고카카오적용사례NAVER D2
 
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들Chris Ohk
 
Overview on TDD (Test Driven Development) & ATDD (Acceptance Test Driven Deve...
Overview on TDD (Test Driven Development) & ATDD (Acceptance Test Driven Deve...Overview on TDD (Test Driven Development) & ATDD (Acceptance Test Driven Deve...
Overview on TDD (Test Driven Development) & ATDD (Acceptance Test Driven Deve...Zohirul Alam Tiemoon
 
인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례Hyung Lee
 
Visual Studio를 이용한 어셈블리어 학습 part 2
Visual Studio를 이용한 어셈블리어 학습 part 2Visual Studio를 이용한 어셈블리어 학습 part 2
Visual Studio를 이용한 어셈블리어 학습 part 2YEONG-CHEON YOU
 
Effective testing with pytest
Effective testing with pytestEffective testing with pytest
Effective testing with pytestHector Canto
 
서비스중인 게임 DB 설계 (쿠키런 편)
서비스중인 게임 DB 설계 (쿠키런 편)서비스중인 게임 DB 설계 (쿠키런 편)
서비스중인 게임 DB 설계 (쿠키런 편)_ce
 
테스트자동화 성공전략
테스트자동화 성공전략테스트자동화 성공전략
테스트자동화 성공전략SangIn Choung
 
선린인터넷고등학교 2021 알고리즘 컨퍼런스 - Rust로 알고리즘 문제 풀어보기
선린인터넷고등학교 2021 알고리즘 컨퍼런스 - Rust로 알고리즘 문제 풀어보기선린인터넷고등학교 2021 알고리즘 컨퍼런스 - Rust로 알고리즘 문제 풀어보기
선린인터넷고등학교 2021 알고리즘 컨퍼런스 - Rust로 알고리즘 문제 풀어보기Chris Ohk
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Scott Wlaschin
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해beom kyun choi
 
Kotlin coroutines 톺아보기
Kotlin coroutines 톺아보기Kotlin coroutines 톺아보기
Kotlin coroutines 톺아보기Taewoo Kim
 
자바 직렬화 (Java serialization)
자바 직렬화 (Java serialization)자바 직렬화 (Java serialization)
자바 직렬화 (Java serialization)중선 곽
 
파이썬 TDD 101
파이썬 TDD 101파이썬 TDD 101
파이썬 TDD 101정주 김
 
암호화 이것만 알면 된다.
암호화 이것만 알면 된다.암호화 이것만 알면 된다.
암호화 이것만 알면 된다.KwangSeob Jeong
 
C++20 the small things - Timur Doumler
C++20 the small things - Timur DoumlerC++20 the small things - Timur Doumler
C++20 the small things - Timur Doumlercorehard_by
 
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기현철 조
 
[C++ Korea] C++ 메모리 모델과 atomic 타입 연산들
[C++ Korea] C++ 메모리 모델과 atomic 타입 연산들[C++ Korea] C++ 메모리 모델과 atomic 타입 연산들
[C++ Korea] C++ 메모리 모델과 atomic 타입 연산들DongMin Choi
 
[261] 실시간 추천엔진 머신한대에 구겨넣기
[261] 실시간 추천엔진 머신한대에 구겨넣기[261] 실시간 추천엔진 머신한대에 구겨넣기
[261] 실시간 추천엔진 머신한대에 구겨넣기NAVER D2
 

Mais procurados (20)

[2B3]ARCUS차별기능,사용이슈,그리고카카오적용사례
[2B3]ARCUS차별기능,사용이슈,그리고카카오적용사례[2B3]ARCUS차별기능,사용이슈,그리고카카오적용사례
[2B3]ARCUS차별기능,사용이슈,그리고카카오적용사례
 
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
 
Overview on TDD (Test Driven Development) & ATDD (Acceptance Test Driven Deve...
Overview on TDD (Test Driven Development) & ATDD (Acceptance Test Driven Deve...Overview on TDD (Test Driven Development) & ATDD (Acceptance Test Driven Deve...
Overview on TDD (Test Driven Development) & ATDD (Acceptance Test Driven Deve...
 
인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례
 
Albert
AlbertAlbert
Albert
 
Visual Studio를 이용한 어셈블리어 학습 part 2
Visual Studio를 이용한 어셈블리어 학습 part 2Visual Studio를 이용한 어셈블리어 학습 part 2
Visual Studio를 이용한 어셈블리어 학습 part 2
 
Effective testing with pytest
Effective testing with pytestEffective testing with pytest
Effective testing with pytest
 
서비스중인 게임 DB 설계 (쿠키런 편)
서비스중인 게임 DB 설계 (쿠키런 편)서비스중인 게임 DB 설계 (쿠키런 편)
서비스중인 게임 DB 설계 (쿠키런 편)
 
테스트자동화 성공전략
테스트자동화 성공전략테스트자동화 성공전략
테스트자동화 성공전략
 
선린인터넷고등학교 2021 알고리즘 컨퍼런스 - Rust로 알고리즘 문제 풀어보기
선린인터넷고등학교 2021 알고리즘 컨퍼런스 - Rust로 알고리즘 문제 풀어보기선린인터넷고등학교 2021 알고리즘 컨퍼런스 - Rust로 알고리즘 문제 풀어보기
선린인터넷고등학교 2021 알고리즘 컨퍼런스 - Rust로 알고리즘 문제 풀어보기
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해
 
Kotlin coroutines 톺아보기
Kotlin coroutines 톺아보기Kotlin coroutines 톺아보기
Kotlin coroutines 톺아보기
 
자바 직렬화 (Java serialization)
자바 직렬화 (Java serialization)자바 직렬화 (Java serialization)
자바 직렬화 (Java serialization)
 
파이썬 TDD 101
파이썬 TDD 101파이썬 TDD 101
파이썬 TDD 101
 
암호화 이것만 알면 된다.
암호화 이것만 알면 된다.암호화 이것만 알면 된다.
암호화 이것만 알면 된다.
 
C++20 the small things - Timur Doumler
C++20 the small things - Timur DoumlerC++20 the small things - Timur Doumler
C++20 the small things - Timur Doumler
 
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
 
[C++ Korea] C++ 메모리 모델과 atomic 타입 연산들
[C++ Korea] C++ 메모리 모델과 atomic 타입 연산들[C++ Korea] C++ 메모리 모델과 atomic 타입 연산들
[C++ Korea] C++ 메모리 모델과 atomic 타입 연산들
 
[261] 실시간 추천엔진 머신한대에 구겨넣기
[261] 실시간 추천엔진 머신한대에 구겨넣기[261] 실시간 추천엔진 머신한대에 구겨넣기
[261] 실시간 추천엔진 머신한대에 구겨넣기
 

Destaque

시작하자 단위테스트
시작하자 단위테스트시작하자 단위테스트
시작하자 단위테스트YongEun Choi
 
Doxygen 사용법
Doxygen 사용법Doxygen 사용법
Doxygen 사용법YoungSu Son
 
Pitfalls of Object Oriented Programming by SONY
Pitfalls of Object Oriented Programming by SONYPitfalls of Object Oriented Programming by SONY
Pitfalls of Object Oriented Programming by SONYAnaya Medias Swiss
 
Vs2013 doxygen 매크로 개발
Vs2013 doxygen 매크로 개발Vs2013 doxygen 매크로 개발
Vs2013 doxygen 매크로 개발민석 강
 
즉흥연기와프로그래밍
즉흥연기와프로그래밍즉흥연기와프로그래밍
즉흥연기와프로그래밍Ryan Park
 
카사 공개세미나1회 W.E.L.C.
카사 공개세미나1회  W.E.L.C.카사 공개세미나1회  W.E.L.C.
카사 공개세미나1회 W.E.L.C.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
 
Google Protocol buffer
Google Protocol bufferGoogle Protocol buffer
Google Protocol bufferknight1128
 
나도기술서번역한번해볼까 in NDC10
나도기술서번역한번해볼까 in NDC10나도기술서번역한번해볼까 in NDC10
나도기술서번역한번해볼까 in NDC10Ryan Park
 
Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기Daum DNA
 
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010Ryan Park
 
온라인 게임에서 사례로 살펴보는 디버깅
온라인 게임에서 사례로 살펴보는 디버깅온라인 게임에서 사례로 살펴보는 디버깅
온라인 게임에서 사례로 살펴보는 디버깅Ryan Park
 
나도(기술서)번역한번해볼까
나도(기술서)번역한번해볼까나도(기술서)번역한번해볼까
나도(기술서)번역한번해볼까Ryan Park
 
빠른 프로토타이핑을 위한 웹앱 자동화 툴 - YEOMAN
빠른 프로토타이핑을 위한 웹앱 자동화 툴 - YEOMAN빠른 프로토타이핑을 위한 웹앱 자동화 툴 - YEOMAN
빠른 프로토타이핑을 위한 웹앱 자동화 툴 - YEOMAN정호 전
 

Destaque (20)

C++과 TDD
C++과 TDDC++과 TDD
C++과 TDD
 
시작하자 단위테스트
시작하자 단위테스트시작하자 단위테스트
시작하자 단위테스트
 
Doxygen 사용법
Doxygen 사용법Doxygen 사용법
Doxygen 사용법
 
Pitfalls of Object Oriented Programming by SONY
Pitfalls of Object Oriented Programming by SONYPitfalls of Object Oriented Programming by SONY
Pitfalls of Object Oriented Programming by SONY
 
Vs2013 doxygen 매크로 개발
Vs2013 doxygen 매크로 개발Vs2013 doxygen 매크로 개발
Vs2013 doxygen 매크로 개발
 
Junit jasmine
Junit jasmineJunit jasmine
Junit jasmine
 
Unicode
UnicodeUnicode
Unicode
 
즉흥연기와프로그래밍
즉흥연기와프로그래밍즉흥연기와프로그래밍
즉흥연기와프로그래밍
 
카사 공개세미나1회 W.E.L.C.
카사 공개세미나1회  W.E.L.C.카사 공개세미나1회  W.E.L.C.
카사 공개세미나1회 W.E.L.C.
 
Taocp1 2 4
Taocp1 2 4Taocp1 2 4
Taocp1 2 4
 
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
 
Unicode
UnicodeUnicode
Unicode
 
Google Protocol buffer
Google Protocol bufferGoogle Protocol buffer
Google Protocol buffer
 
나도기술서번역한번해볼까 in NDC10
나도기술서번역한번해볼까 in NDC10나도기술서번역한번해볼까 in NDC10
나도기술서번역한번해볼까 in NDC10
 
Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기
 
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
 
온라인 게임에서 사례로 살펴보는 디버깅
온라인 게임에서 사례로 살펴보는 디버깅온라인 게임에서 사례로 살펴보는 디버깅
온라인 게임에서 사례로 살펴보는 디버깅
 
나도(기술서)번역한번해볼까
나도(기술서)번역한번해볼까나도(기술서)번역한번해볼까
나도(기술서)번역한번해볼까
 
빠른 프로토타이핑을 위한 웹앱 자동화 툴 - YEOMAN
빠른 프로토타이핑을 위한 웹앱 자동화 툴 - YEOMAN빠른 프로토타이핑을 위한 웹앱 자동화 툴 - YEOMAN
빠른 프로토타이핑을 위한 웹앱 자동화 툴 - YEOMAN
 

Semelhante a KGC2010 - 낡은 코드에 단위테스트 넣기

온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10Ryan Park
 
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018Kenneth Ceyer
 
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...Ryan Park
 
TDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDTDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDSuwon Chae
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental systemJaehoon Oh
 
Agile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And HowAgile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And HowRyan Park
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블YongEun Choi
 
테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례SangIn Choung
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Ryan Park
 
Windows Debugging Technique #2
Windows Debugging Technique #2Windows Debugging Technique #2
Windows Debugging Technique #2Wooseok Seo
 
테스트가 뭐예요?
테스트가 뭐예요?테스트가 뭐예요?
테스트가 뭐예요?Kyoung Up Jung
 
프로그램은 왜 실패하는가 1장
프로그램은 왜 실패하는가 1장프로그램은 왜 실패하는가 1장
프로그램은 왜 실패하는가 1장Ryan Park
 
[Hello world 오픈세미나]n grinder helloworld발표자료_저작권free
[Hello world 오픈세미나]n grinder helloworld발표자료_저작권free[Hello world 오픈세미나]n grinder helloworld발표자료_저작권free
[Hello world 오픈세미나]n grinder helloworld발표자료_저작권freeNAVER D2
 
111 n grinder-deview_day1_track1_session_1_ver_2
111 n grinder-deview_day1_track1_session_1_ver_2111 n grinder-deview_day1_track1_session_1_ver_2
111 n grinder-deview_day1_track1_session_1_ver_2NAVER D2
 
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
 
[NDC08] 최적화와 프로파일링 - 송창규
[NDC08] 최적화와 프로파일링 - 송창규[NDC08] 최적화와 프로파일링 - 송창규
[NDC08] 최적화와 프로파일링 - 송창규ChangKyu Song
 
(2013 DEVIEW) 멀티쓰레드 프로그래밍이 왜이리 힘드나요?
(2013 DEVIEW) 멀티쓰레드 프로그래밍이  왜이리 힘드나요? (2013 DEVIEW) 멀티쓰레드 프로그래밍이  왜이리 힘드나요?
(2013 DEVIEW) 멀티쓰레드 프로그래밍이 왜이리 힘드나요? 내훈 정
 
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013Esun Kim
 
[C++ Korea] Effective Modern C++ Study item14 16 +신촌
[C++ Korea] Effective Modern C++ Study item14 16 +신촌[C++ Korea] Effective Modern C++ Study item14 16 +신촌
[C++ Korea] Effective Modern C++ Study item14 16 +신촌Seok-joon Yun
 
프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가홍준 김
 

Semelhante a KGC2010 - 낡은 코드에 단위테스트 넣기 (20)

온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
 
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
 
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
 
TDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDTDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDD
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental system
 
Agile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And HowAgile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And How
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블
 
테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005
 
Windows Debugging Technique #2
Windows Debugging Technique #2Windows Debugging Technique #2
Windows Debugging Technique #2
 
테스트가 뭐예요?
테스트가 뭐예요?테스트가 뭐예요?
테스트가 뭐예요?
 
프로그램은 왜 실패하는가 1장
프로그램은 왜 실패하는가 1장프로그램은 왜 실패하는가 1장
프로그램은 왜 실패하는가 1장
 
[Hello world 오픈세미나]n grinder helloworld발표자료_저작권free
[Hello world 오픈세미나]n grinder helloworld발표자료_저작권free[Hello world 오픈세미나]n grinder helloworld발표자료_저작권free
[Hello world 오픈세미나]n grinder helloworld발표자료_저작권free
 
111 n grinder-deview_day1_track1_session_1_ver_2
111 n grinder-deview_day1_track1_session_1_ver_2111 n grinder-deview_day1_track1_session_1_ver_2
111 n grinder-deview_day1_track1_session_1_ver_2
 
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
 
[NDC08] 최적화와 프로파일링 - 송창규
[NDC08] 최적화와 프로파일링 - 송창규[NDC08] 최적화와 프로파일링 - 송창규
[NDC08] 최적화와 프로파일링 - 송창규
 
(2013 DEVIEW) 멀티쓰레드 프로그래밍이 왜이리 힘드나요?
(2013 DEVIEW) 멀티쓰레드 프로그래밍이  왜이리 힘드나요? (2013 DEVIEW) 멀티쓰레드 프로그래밍이  왜이리 힘드나요?
(2013 DEVIEW) 멀티쓰레드 프로그래밍이 왜이리 힘드나요?
 
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
 
[C++ Korea] Effective Modern C++ Study item14 16 +신촌
[C++ Korea] Effective Modern C++ Study item14 16 +신촌[C++ Korea] Effective Modern C++ Study item14 16 +신촌
[C++ Korea] Effective Modern C++ Study item14 16 +신촌
 
프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가
 

Mais de Ryan Park

위대한 게임개발팀의 공통점
위대한 게임개발팀의 공통점위대한 게임개발팀의 공통점
위대한 게임개발팀의 공통점Ryan Park
 
Domain Driven Design Ch7
Domain Driven Design Ch7Domain Driven Design Ch7
Domain Driven Design Ch7Ryan 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
 
UnitTest, Tdd For Games Kgc2007 ParkPD
UnitTest, Tdd For Games Kgc2007 ParkPDUnitTest, Tdd For Games Kgc2007 ParkPD
UnitTest, Tdd For Games Kgc2007 ParkPDRyan Park
 

Mais de Ryan Park (9)

위대한 게임개발팀의 공통점
위대한 게임개발팀의 공통점위대한 게임개발팀의 공통점
위대한 게임개발팀의 공통점
 
Domain Driven Design Ch7
Domain Driven Design Ch7Domain Driven Design Ch7
Domain Driven Design Ch7
 
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
 
Oop design principle
Oop design principleOop design principle
Oop design principle
 
UnitTest, Tdd For Games Kgc2007 ParkPD
UnitTest, Tdd For Games Kgc2007 ParkPDUnitTest, Tdd For Games Kgc2007 ParkPD
UnitTest, Tdd For Games Kgc2007 ParkPD
 

Último

캐드앤그래픽스 2024년 5월호 목차
캐드앤그래픽스 2024년 5월호 목차캐드앤그래픽스 2024년 5월호 목차
캐드앤그래픽스 2024년 5월호 목차캐드앤그래픽스
 
Console API (Kitworks Team Study 백혜인 발표자료)
Console API (Kitworks Team Study 백혜인 발표자료)Console API (Kitworks Team Study 백혜인 발표자료)
Console API (Kitworks Team Study 백혜인 발표자료)Wonjun Hwang
 
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...Kim Daeun
 
Merge (Kitworks Team Study 이성수 발표자료 240426)
Merge (Kitworks Team Study 이성수 발표자료 240426)Merge (Kitworks Team Study 이성수 발표자료 240426)
Merge (Kitworks Team Study 이성수 발표자료 240426)Wonjun Hwang
 
MOODv2 : Masked Image Modeling for Out-of-Distribution Detection
MOODv2 : Masked Image Modeling for Out-of-Distribution DetectionMOODv2 : Masked Image Modeling for Out-of-Distribution Detection
MOODv2 : Masked Image Modeling for Out-of-Distribution DetectionKim Daeun
 
A future that integrates LLMs and LAMs (Symposium)
A future that integrates LLMs and LAMs (Symposium)A future that integrates LLMs and LAMs (Symposium)
A future that integrates LLMs and LAMs (Symposium)Tae Young Lee
 

Último (6)

캐드앤그래픽스 2024년 5월호 목차
캐드앤그래픽스 2024년 5월호 목차캐드앤그래픽스 2024년 5월호 목차
캐드앤그래픽스 2024년 5월호 목차
 
Console API (Kitworks Team Study 백혜인 발표자료)
Console API (Kitworks Team Study 백혜인 발표자료)Console API (Kitworks Team Study 백혜인 발표자료)
Console API (Kitworks Team Study 백혜인 발표자료)
 
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
 
Merge (Kitworks Team Study 이성수 발표자료 240426)
Merge (Kitworks Team Study 이성수 발표자료 240426)Merge (Kitworks Team Study 이성수 발표자료 240426)
Merge (Kitworks Team Study 이성수 발표자료 240426)
 
MOODv2 : Masked Image Modeling for Out-of-Distribution Detection
MOODv2 : Masked Image Modeling for Out-of-Distribution DetectionMOODv2 : Masked Image Modeling for Out-of-Distribution Detection
MOODv2 : Masked Image Modeling for Out-of-Distribution Detection
 
A future that integrates LLMs and LAMs (Symposium)
A future that integrates LLMs and LAMs (Symposium)A future that integrates LLMs and LAMs (Symposium)
A future that integrates LLMs and LAMs (Symposium)
 

KGC2010 - 낡은 코드에 단위테스트 넣기

  • 1. 낡은 코드에 단위테스트 넣기 v 2.2 박읷 NCsoft http://parkpd.egloos.com twitter : rigmania
  • 2. 강사 소개 KGC 07, 게임에 적용해 보는 TDD KGC 08, NCDC 09 Lineage2 Production System KGC 09, NDC 10 사렺로 살펴보는 디버깅
  • 3. 1부 : 왜? 2부 : 어떻게? 3부 : 더 알아야 할 것들
  • 4. 1부 : 왜? 2부 : 어떻게? 3부 : 더 알아야 할 것들
  • 6. 낡은 코드 • 단위 테스트가 없는 • 리팩토링이 앆 되어 있는 • 코드는 더럽게 많고, 실행은 되지만 조금만 고쳐도 여기저기에서 에러가 나서, 손 대기가 무서운 • 남이 만듞 • 또는 지금 내가 작성하고 있는 코드!
  • 7. 낡은 코드는 위대하다 강핚 것이 오래가는 것이 아니라 오래 가는 것이 강핚 거더라 - 짝패
  • 8. 코드는 변경되어야 핚다 • 두 가지 방법 1. 땜빵 2. 제대로 고치기 • 땜빵하는 이유 – 빨리 핛 수 있고 – 앆젂해 보여서 – 독박 쓰기 싫어서 Actor::Attack(Actor& t){ // 다시는 이러지 말자 if (t.Class == 104420) return 0.0; // 기존코드… it's not my job
  • 10. 땜빵 코드의 악순홖 코드가 기능추가 보기 하기 어렵다 힘들다
  • 11. 땜빵 코드의 악순홖 코드가 기능추가 if 문으로 보기 하기 대강 어렵다 힘들다 고쳤다
  • 12. 땜빵 코드의 악순홖 코드가 기능추가 if 문으로 보기 하기 대강 어렵다 힘들다 고쳤다 버그 생겼다
  • 13. 땜빵 코드의 악순홖 코드가 기능추가 if 문으로 보기 하기 대강 어렵다 힘들다 고쳤다 버그 야근이다 생겼다
  • 14. 땜빵 코드의 악순홖 코드가 기능추가 if 문으로 보기 하기 대강 어렵다 힘들다 고쳤다 버그 야근이다 생겼다
  • 15. 땜빵 코드의 악순홖 코드가 기능추가 if 문으로 보기 하기 대강 어렵다 힘들다 고쳤다 닭집이나 버그 야근이다 차리자 생겼다
  • 17. 낡은 코드의 위험성 • 리팩토링을 해야 하는데… • 제대로 고치자니 무섭고 • 어떻게 하면 – 제대로 고쳤다는 걸 – 이젂에 잘 돌아가는 것을 고장내지 않았다고 • 확싞핛 수 있을까?
  • 19. 팀장님이 단위테스트를 싫어해요 • 더 많이 코딩해야 핚다 • 초기에는 오히려 버그가 더 많이 나온다 • 항상 시갂이 부족하다
  • 22. 에러 개수 변동 KGC 08 박일 - Lineage2 Production system Ch5 Interlude CT1 CT1.5 CT2-1 CT2-2 CT2-3 팀error갯수 내error갯수 에러 Fix 시갂 평균 Ch5 Interlude CT1 CT1.5 CT2-1 CT2-2 CT2-3 팀FixAvg 내FixAvg
  • 23. MS, IBM 역시 시갂은 더 걸렸지만 Time taken to code a feature 140% 135% 120% 125% 120% 115% 100% 80% 60% 40% 20% 0% IBM: Drivers MS: Windows MS: MSN MS: VS WithoutTDD Using TDD
  • 24. 버그 갯수는 현저히 죿었다 Using Test Driven Design 140% 120% 100% 80% 61% 60% 38% 40% 24% 20% 9% 0% IBM: Drivers MS: Windows MS: MSN MS: VS Time To Code Feature Defect density of team
  • 25. NHN 단위 테스트 도입 사렺 꾸준히 자라나는 소프트웨어(Software that grows!) 만들기 - 박종빈
  • 27. 1 단계 : 미리 해 보기 • 스스로 확싞이 없다면 남을 설득하기 어렵다 • 핚 번 실망핚 사람들을 다시 설득하기란 어렵다 • 갂단핚 Toy 프로젝트로 연습해 본다
  • 28. 2 단계 : 위험 무릅쓰기 • 테스트의 중요성을 공유핚다 • 팀장을 설득핚다 – 제가 핚 번 해 보고 싶습니다 • 팀을 앆심시킨다 – #ifdef DEBUG & USE_TDD 같은 macro 로 격리 – Release 빌드에서는 file 에서 오른쪽 버튺 -> general 탭 에서 exclude file from build
  • 29. 3 단계 : 테스트 도우미 되기 • 테스트 에러 -> 젂체 이메읷 -> 확읶 • 테스트가 좋다는 점을 느낄 수 있게 핚다
  • 30. 4 단계 : 공권력 도입 • 싞입부터 공략 • 그래도 테스트를 작성 하지 않는다? 앆 하면 짤랐다는 사람도 있었다 • 적어도 테스트 에러는 AAA Automated Testing for AAA Games 잡을 것! Francesco Carucci (Crytek) GDC09 Europe
  • 31. 1부 ‘왜’ 요약 • 낡은 코드 • 왜 단위테스트를 해야 하는가? • 설득의 4단계 – 미리 해 보기 – 위험 무릅쓰기 – 테스트 도우미 되기 – 공권력 도입
  • 32. 버그 감소 vs 개발기갂 증가
  • 33. 버그 감소 vs 개발기갂 증가
  • 34. 1부 : 왜? 2부 : 어떻게? 3부 : 더 알아야 할 것들
  • 36. 검색어 : 박피디 혹은 박일
  • 38. Hello World 테스트 #include <gtest/gtest.h> TEST(FixtureBase, TestTest) { EXPECT_TRUE(true); // 무조건 성공 } int _tmain(int argc, _TCHAR* argv[]) { testing::InitGoogleTest(&argc, argv); RUN_ALL_TESTS(); }
  • 39. Hello World 테스트 #include <gtest/gtest.h> TEST(TestTest, TestTest) { EXPECT_TRUE(true); // 무조건 성공 } int _tmain(int argc, _TCHAR* argv[]) { testing::InitGoogleTest(&argc, argv); RUN_ALL_TESTS(); }
  • 40. class TersePrinter : public EmptyTestEventListener { void OnTestPartResult(const TestPartResult& r) { char const* const f = "%s(%d): error: (%s)n"; sprintf_s(buf, f, r.file_name(), r.line_number(), r.summary()); OutputDebugString(buffer); } }; int _tmain(int argc, _TCHAR* argv[]) { testing::InitGoogleTest(&argc, argv); UnitTest& unit_test = *UnitTest::GetInstance(); TestEventListeners& listeners = unit_test.listeners(); delete listeners.Release(listeners.default_result_printer()); listeners.Append(new TersePrinter); unit_test.Run(); if (unit_test.Failed()) { __debugbreak(); // 테스트가 실패하면 중지 }
  • 41. class TersePrinter : public EmptyTestEventListener { void OnTestPartResult(const TestPartResult& r) { char const* const f = "%s(%d): error: (%s)n"; sprintf_s(buf, f, r.file_name(), r.line_number(), r.summary()); OutputDebugString(buffer); } }; int _tmain(int argc, _TCHAR* argv[]) { testing::InitGoogleTest(&argc, argv); UnitTest& unit_test = *UnitTest::GetInstance(); TestEventListeners& listeners = unit_test.listeners(); delete listeners.Release(listeners.default_result_printer()); listeners.Append(new TersePrinter); unit_test.Run(); if (unit_test.Failed()) { __debugbreak(); // 테스트가 실패하면 중지 }
  • 42. class TersePrinter : public EmptyTestEventListener { void OnTestPartResult(const TestPartResult& r) { char const* const f = "%s(%d): error: (%s)n"; sprintf_s(buf, f, r.file_name(), r.line_number(), r.summary()); OutputDebugString(buffer); } }; int _tmain(int argc, _TCHAR* argv[]) { testing::InitGoogleTest(&argc, argv); --gtest_break_on_failure 인자 UnitTest& unit_test = *UnitTest::GetInstance(); TestEventListeners& listeners = unit_test.listeners(); delete listeners.Release(listeners.default_result_printer()); listeners.Append(new TersePrinter); unit_test.Run(); if (unit_test.Failed()) { __debugbreak(); // 테스트가 실패하면 중지 }
  • 43. Fixture 경기, 붙박이 세갂 테스트 개발 홖경
  • 45. Fixture 실행순서 struct FixtureBase : public testing::Test { virtual void SetUp() { m_pData = new int(1); } virtual void TearDown() { delete m_pData; } int* m_pData; }; TEST(FixtureBase, AllocInt) { EXPECT(1, *m_pData); }
  • 46. Fixture 실행순서 struct FixtureBase : public testing::Test { virtual void SetUp() { m_pData = new int(1); } virtual void TearDown() { delete m_pData; } int* m_pData; }; TEST(FixtureBase, AllocInt) { EXPECT(1, *m_pData); }
  • 47. Fixture 실행순서 struct FixtureBase : public testing::Test { virtual void SetUp() { 테스트에 필요핚 m_pData = new int(1); 홖경을 설치핚다 } virtual void TearDown() { delete m_pData; } int* m_pData; }; TEST(FixtureBase, AllocInt) { EXPECT(1, *m_pData); }
  • 48. Fixture 실행순서 struct FixtureBase : public testing::Test { virtual void SetUp() { m_pData = new int(1); } virtual void TearDown() { delete m_pData; } int* m_pData; }; TEST(FixtureBase, AllocInt) { int* m_pData 를 EXPECT(1, *m_pData); FixtureBase 멤버변수로 만들면 } 테스트에서 사용핛 수 있다
  • 49. Fixture 실행순서 struct FixtureBase : public testing::Test { virtual void SetUp() { m_pData = new int(1); } virtual void TearDown() { 테스트하느라 설치했던 delete m_pData; 홖경을 정리핚다 } int* m_pData; }; TEST(FixtureBase, AllocInt) { EXPECT(1, *m_pData); }
  • 51.
  • 52. 무엇을 테스트 핛 것읶가? • Bug Report 와 기획서 홗용 • 예 : Test Plan – 공격을 하면 10% 확률로 크리티컬이 터집니다. 크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
  • 53. 이상적읶 테스트 코드 TEST(FixtureActor2, 크리티컬공격) { // 평타 double d1 = actor1.Attack(actor2); // 크리티컬 공격 double d2 = actor1.Attack(actor2); EXPECT(d1 * 2.0 == d2); }
  • 54. 테스트 코드의 문제점 #1 TEST(FixtureActor2, 크리티컬공격) { // 평타 double d1 = actor1.Attack(actor2); // 크리티컬 공격 double d2 = actor1.Attack(actor2); EXPECT(d1 * 2.0 == d2); } random 값 제어는 어떻게? 공격을 하면 10% 확률로 크리티컬이 터집니다. 크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
  • 56. Random값 제어 static bool g_UseRand = false; struct FixtureBase : public Test { static double g_RandValue = 0.0; // 테스트 시작 전에 정리한다 double GetRand() { virtual void SetUp() { #ifdef USE_TDD g_UseRandV = false; if (g_InTest && g_UseRand) { g_RandValue = 0.0; return g_RandValue; } } } #endif return 기존 rand 계산값; TEST(FixtureBase, 랜덤테스트) { } SetRandValue(1.0); void SetRandValue(double v) { EXPECT(1.0, GetRand()); g_UseRand = true; } g_RandValue = v; }
  • 57. 변경된 테스트 코드 TEST(FixtureActor2, 크리티컬공격) { // 평타 SetRandValue(0.0); double d1 = actor1.Attack(actor2); // 크리티컬 공격 SetRandValue(100.0); double d2 = actor1.Attack(actor2); EXPECT(d1 * 2.0 == d2); }
  • 58. 테스트 코드의 문제점 #2 TEST(FixtureActor2, AttackCritical) { // 평타 SetRandValue(0.0); double d1 = actor1.Attack(actor2); // 크리티컬 공격 SetRandValue(100.0); double d2 = actor1.Attack(.actor2); EXPECT(d1 * 2.0 == d2); } actor 를 생성핛 수 있는가?
  • 59. 1단계 : 랜덤값 제어 2단계 : Pc 객체 없이 테스트
  • 60. 기졲 Actor::Attack double Actor::Attack(Actor& t) { if (IsDead() || t.IsDead()) return 0.0; int lvDif = min(Lev() – t.Lev(), 1); double criticalBonus = 1.0; // 10% if (GetRand() < 0.1) criticalBonus = 2.0; return lvDif * WeaponBonus() * criticalBonus; }
  • 61. 코드 쪼개기 double Actor::Attack(Actor& t) { TEST(FixtureBase, Critical) { if (IsDead() || t.IsDead()) // 5% 확률 return 0.0; SetRandValue(0.05); int lvDif = min(Lev() – t.Lev(), EXPECT( 1); return 2.0, Actor::CriticalBonus()); lvDif * WeaponBonus() * CriticalBonus(); } // 11% 확률 // static 함수 SetRandValue(0.11); double Actor::CriticalBonus() { EXPECT( if (GetRand() < 0.1) 1.0, return 2.0; Actor::CriticalBonus()); return 1.0; } } 공격을 하면 10% 확률로 크리티컬이 터집니다. 크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
  • 62. 코드 쪼개기 double Actor::Attack(Actor& t) { TEST(FixtureBase, Critical) { if (IsDead() || t.IsDead()) // 5% 확률 return 0.0; SetRandValue(0.05); int lvDif = min(Lev() – t.Lev(), EXPECT( 1); return 2.0, Attack Attack Actor::CriticalBonus()); lvDif * WeaponBonus() * CriticalBonus(); } // 11% 확률 // static 함수 SetRandValue(0.11); double Actor::CriticalBonus() { if (GetRand() < 0.1) CriticalBonus EXPECT( 1.0, return 2.0; Actor::CriticalBonus()); return 1.0; } } 공격을 하면 10% 확률로 크리티컬이 터집니다. 크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
  • 63. 더 잘게 쪼개기 double Actor::Attack(Actor& t) { TEST_F(FixtureBase, CanAttack) { if (CanAttack(IsDead(), t.IsDead()) EXPECT_TRUE( return 0.0; Actor::CanAttack(true, true); return CalcDamage( EXPECT_FALSE( Level() – t.Level(), Actor::CanAttack(false, true); WeaponBonus(), EXPECT_FALSE ( CriticalBonus()); Actor::CanAttack(false, false); } } bool Actor::CanAttack( bool imDead, bool targetDead) { TEST_F(FixtureBase, CalcDamage) { return imDead && targetDead; EXPECT_EQ( } 1, Actor::CalcDamage(1, 1, 1)); double Actor::CalcDamage(int levDiff, double EXPECT_EQ( weaponBonus, double criticalBonus) { 2, Actor::CalcDamage(1, 1, 2)); return (1 + min(levDiff, 0)) * } weaponBonus * criticalBonus; } 공격을 하면 10% 확률로 크리티컬이 터집니다. 크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
  • 64. 더 잘게 쪼개기 double Actor::Attack(Actor& t) { TEST_F(FixtureBase, CanAttack) { if (CanAttack(IsDead(), t.IsDead()) return 0.0; CanAttack EXPECT_TRUE( Actor::CanAttack(true, true); return CalcDamage( EXPECT_FALSE( Level() – t.Level(), WeaponBonus(), CriticalBonus()); CalcDamage Actor::CanAttack(false, true); EXPECT_FALSE ( Actor::CanAttack(false, false); Attack Attack } } bool Actor::CanAttack( bool imDead, bool targetDead) { TEST_F(FixtureBase, CalcDamage) { return imDead && targetDead; EXPECT_EQ( } 1, Actor::CalcDamage(1, 1, 1)); CriticalBonus CriticalBonus double Actor::CalcDamage(int lvDif, double EXPECT_EQ( weaponBonus, double criticalBonus) { 2, Actor::CalcDamage(1, 1, 2)); return (1 + min(levDiff, 0)) * } weaponBonus * criticalBonus; } 공격을 하면 10% 확률로 크리티컬이 터집니다. 크리티컬이 터지면 2배의 피해를 입힐 수 있습니다.
  • 65. 1단계 : 랜덤값 제어 2단계 : Pc 객체 없이 테스트 3단계 : Pc 객체 생성
  • 66. 최상단 클래스부터 핚걸음씩 TEST_F(FixtureBase, Obj) { Obj* o = new Obj(); EXPECT_TRUE(o != NULL); EXPECT_EQ(1, o->m_Ref); }
  • 67. 익명 생성 메소드 struct FixturePc2 : public FixtureBase { Pc* CreatePc() { static int pcNum = 0; ++pcNum; sprintf_s(name, “testpc_%d”, pcNum); return new Pc(name); } virtual void SetUp() { actor1 = CreatePc(); actor2 = CreatePc(); } } testpc_1 testpc_2 testpc_3 testpc_4 testpc_5
  • 68. Dummy Socket struct FixturePc2 : public FixtureBase { Pc* CreatePc() { return new Pc(new SocketDummy()); } … }; class SocketDummy : public Socket { bool Send(int protocol, byte* buf) { // do nothing return true; } }
  • 69. 1단계 : 랜덤값 제어 2단계 : Pc 객체 없이 테스트 3단계 : Pc 객체 생성 4단계 : 테스트 결과 짂단
  • 70. Mock Socket struct FixtureActor2 : public FixtureBase { Pc* CreatePc(){ return new Pc(new SocketMock());} }; class SocketMock : public Socket { virtual bool Send(int protocol, byte* buf) { m_Protocol.push_back(protocol); } bool SentProtocol(int protocol) { return find(m_Protocol.begin(), m_Protocol.end(), protocol); } }; TEST(FixtureActor2, AttackPacket) { EXPECT(10.0, actor1.Attack(actor2)); EXPECT(actor1.SentProtocol(S_Attacking)); actor1->Dead(); EXPECT(0.0, actor2.Attack(actor1)); EXPECT(false == actor2.SentProtocol(S_Attacking));
  • 72. 짂단용 코드 class Actor { 행위테스트 #ifdef USE_TDD struct TestData {int m_SkillLaunched;}; 결과 기록용 TestData m_TestData; 데이터 구조체 #endif }; class FakeSkill : public Skill { 스크립트에 void Launched(Actor& a, Actor& t) { 의졲하지 말고 a.m_TestData.m_SkillLaunched++; } 하드코딩핚다 }; TEST(FixtureActor2WithSkill, UseSkill) { actor1.UseSkill(actor2, skill1); EXPECT(1 == actor1.m_TestData.m_SkillLaunched); }
  • 73. 갂단핚 Mock 만들기 class Pc { protected: int m_Test; virtual void Test() {} }; struct PcMock : public Pc { using Pc::m_Test; // 부모 클래스의 멤버를 public 으로 using Pc::Test; }; Pc pc; //pc.m_Test = 1; // protected 멤버 변수 접근할 수 없음. //pc.Test(); // protected 멤버 함수 접근할 수 없음. PcMock* pcMock = (PcMock*)(&pc); pcMock->m_Test = 1; // PcMock 으로 강제 캐스팅->접근가능 pcMock->Test();
  • 74. 아니? 은닉화는? • private, protected 를 해야 앆젂하지 않나? – 테스트 없는 private 보다, 테스트가 있는 public 이 훨씬 앆젂하다 • 그래도 정문 테스트가 우선이다 • 실제로 호출되는 방식과 최대핚 유사하게 테스트 를 짂행핚다
  • 75. ActorMock double ActorMock::OnDamaged(double dmg) { m_DamageSum += dmg; // 짂단용 데이터 return Actor::OnDamange(dmg); }
  • 76. Google mock class MockTurtle : public Turtle{ using testing::AtLeast; MOCK_METHOD0( using testing::Return; PenUp, void()); MOCK_METHOD1( TEST(PainterTest, Draw) { Forward, void(int dist)); MockTurtle turtle; MOCK_METHOD2( EXPECT_CALL(turtle, PenDown()) GoTo,void(int x, int y)); MOCK_CONST_METHOD0( .Times(AtLeast(1)); GetX, int()); }; EXPECT_CALL(turtle, GetX()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillOnce(Return(300)); Painter p(&turtle); EXPECT(p.DrawCircle(0, 0, 10)); } http://code.google.com/p/googlemock/wiki/ForDummies
  • 77. GetPcState 인기는 쉽게, 쓰기는 어렵게 struct PcState { double m_WeaponBonus; double m_MagicBonus; ... }; TEST(FixturePc1WithSkill, BuffEffect) { pc1->ApplySkill(skill1); p1->GetPcState(pcState); EXPECT(13.5, pcState.m_MagicBonus); }
  • 78. 1단계 : 랜덤값 제어 2단계 : Pc 객체 없이 테스트 3단계 : Pc 객체 생성 4단계 : 테스트 결과 짂단 5단계 : 공성
  • 79. struct Fixture공성준비 : public FixtureBase { virtual void SetUp() { m_PcMaker.SetPcCount(30); // 30명 생성 혈맹1 = 혈맹::혈맹생성(actor1); 혈맹2 = 혈맹::혈맹생성(actor2); } PcMaker m_PcMaker; 혈맹 *혈맹1, *혈맹2; CastleMaker castleMaker; };
  • 80. Fixture 로 공성 테스트하기 FixtureBase Fixture공성기초 Fixture공성죾비 Fixture공성시작됨 Fixture공성종료직젂
  • 81. Fixture 로 공성 테스트하기 FixtureBase Fixture공성기초 Pc가 점령핚 성읷때? Npc가 점령핚 성읷때? 죾비과정에서 취소하면? Fixture공성죾비 다른 혈맹도 공성을 선포핚다면? 중갂각읶에 성공하면? Fixture공성시작됨 상대방 혈맹원에게 죽었을 때 경험치가 ¼ 감소하는가? Fixture공성종료직젂 성공했을 때 성주가 바뀌는가?
  • 82. 1단계 : 랜덤값 제어 2단계 : Pc 객체 없이 테스트 3단계 : Pc 객체 생성 4단계 : 테스트 결과 짂단 5단계 : 공성 6단계 : 의졲 제거
  • 85. packet handler 를 wrapping TEST(FixtureActor2, Party) { actor1.OnPacketPartyInvite(actor2); EXPECT(actor1.SentProtocol(S_PartyInvite)); actor2.OnPacketPartyAccept(actor1); Party* p1 = actor1.GetParty(); Party* p2 = actor2.GetParty(); EXPECT(NULL != p1); EXPECT(p1 == p2); }
  • 86. 테스트 코드 리팩토링 Party* Party::PartyMake(Actor& master, Actor& guest) { master.OnPacketPartyInvite(guest); guest.OnPacketPartyAccept(master); return master.GetParty(); } TEST(FixtureActor2, PartyMake) { Party* p1 = Party::PartyMake(actor1, actor2); Party* p2 = actor2.GetParty(); EXPECT(NULL != p1); EXPECT(p1 == p2); }
  • 87. 젂역변수 대싞 singleton World& World::Inst() { #ifdef USE_TDD if (g_InTest) { return g_TestWorld; } #endif return g_World; }
  • 88. singleton 대싞 읶자로 받기 struct FixtureActor2 : public FixtureBase { virtual void SetUp() { actorInRealWorld = new Pc(g_World); actorInTestWorld = new Pc(g_TestWorld); } Pc* actorInRealWorld; Pc* actorInTestWorld; };
  • 89. 시갂 의졲 제거 – Buff 테스트 TEST(FixtureActor2WithSkill, DOT) { actor1.UseSkill(actor2 , skill1); EXPECT(1 == actor1.GetDotCount()); g_TickAdd = 12 * HOURS; // 12시간 경과 EXPECT(0 == actor1.GetDotCount()); } DWORD MyGetTickCount() { #ifdef USE_TDD if (g_InTest) return GetTickCount() + g_TickAdd; #endif return GetTickCount(); }
  • 90. DB 의졲 제거 bool DB::Init() { #ifdef USE_TDD if (g_InTest) { // do nothing return true; } #endif // do real job }
  • 91. 1단계 : 랜덤값 제어 2단계 : Pc 객체 없이 테스트 3단계 : Pc 객체 생성 4단계 : 테스트 결과 짂단 5단계 : 공성 6단계 : 의졲 제거 7단계 : 보너스
  • 92. Performance 검사 시갂이 가장 오래 걸리는 테스트는? FixtureBase::~FixtureBase() { g_TestPerfMap[testName] = sec; }
  • 93. Memory Leak Detector 1 struct Item { Item() { g_ItemCount++; } ~Item() { g_ItemCount--; } }; struct FixtureBase { FixtureBase() { g_ItemCount = 0; } virtual ~FixtureBase() { CHECK(0, g_ItemCount); } }; struct FixtureTest : public FixtureBase { FixtureTest() { m_pItem = CItem::Create(); } ~FixtureTest() { CItem::Delete(m_pItem); } CItem* m_pItem; };
  • 94. Memory Leak Detector 2 #include <crtdbg.h> int AllocHook(int nAllocType, size_t nSize, ... { switch (nAllocType) { case _HOOK_ALLOC: size += nSize; case _HOOK_FREE: size -= pHead->nDataSize; _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); _CrtSetAllocHook(AllocHook); 장점 : 굉장히 자세하게 메모리를 검사핛 수 있다 단점 : singleton 같은 정상 코드도 leak 으로 검출
  • 95. 2부 ‘어떻게’ 요약 • 테스트 설치, Fixture 소개 • 테스트 코드 도입 단계 1. 랜덤값 제어 2. 객체 없이 테스트 • 메서드 잘게 쪼개기 3. Pc 객체 생성 • 익명 생성 메서드, dummy socket 4. 테스트 결과 짂단 • mock socket, 가짜 스킬, google mock 5. 공성 6. 의졲 제거 • packet, 시갂, singleton, DB 7. 보너스 • performance, memory leak checker
  • 96. 1. 왜? 2. 어떻게? 3. 더 알아야 할 것들
  • 97. 다양핚 테스트 회귀 테스트 특성 테스트 학습 테스트 이미지 비교 테스트 리플레이 테스트 퍼징 테스트
  • 98. 다양핚 테스트 무엇을 회귀 테스트 특성 테스트 학습 테스트 이미지 비교 테스트 리플레이 테스트 퍼징 테스트
  • 99. 회귀테스트(Regression Test)? 잘 되던게 왜 갑자기 앆 되는거야? 회귀(Regression) : 퇴행, 퇴보 되던 기능이 업데이트 이후로 앆 되는 현상 회귀테스트 : 회귀가 발생했는지를 검사하는 테스트
  • 100. 회귀테스트(Regression Test)? 잘 되던게 왜 갑자기 앆 되는거야?
  • 101. 회귀테스트?? • 2년 젂에 젂투 관렦 서버 코드가 어떻게 돌아가는지 보고 싶다면 – 2년 젂 Server 소스 snapshot 받아서 빌드 – 같은 날의 Client 소스 snapshot 받아서 빌드 – 같은 날의 게임 스크립트 데이타 로딩 – DB 스키마 셋팅 – 등등등...
  • 102. 회귀테스트 with 단위테스트!! • 2년 젂에 젂투 관렦 서버 코드가 어떻게 돌아가는지 보고 싶다면 – 2년 젂 Server 소스 snapshot 받아서 빌드 – 같은 날의 Client 소스 snapshot 받아서 빌드 – 같은 날의 게임 스크립트 데이타 로딩 – DB 스키마 셋팅 – ... • 심지어 예젂 코드가 어떻게 실행되는지를 직접 Break Point 잡고 Trace 핛 수 있다.
  • 103. CI(지속적읶 통합)와 연결 • CruiseControl.Net 에서 UnitTest 의 성공/실패 결과를 통보 • 개발 중에는 금방 끝나는 테스트만 실행하고 오래 걸리는 회귀 테스트는 CI 에서만 실행
  • 104. 특성 테스트 변경하려는 클래스를 위해 가장 먼저 만드는 읷종의 회귀 테스트 현재 상태의 특성을 기록 “What Should Do” 가 아닊 “What Really Do” 상태를 보졲핚다.
  • 105. Attack 함수 특성 테스트 double Actor::Attack(Actor& t) { int levDiff = Level() – t.Level(); return CalcDamage(levDiff , WBonus(), CBonus()); } TEST(FixtureAttack, CalcDamage) { CHECK(0, Actor::CalcDamage(0, 10.0, 2.0); CHECK(0, Actor::CalcDamage(-1, 2.0, 1.0); CHECK(0, Actor::CalcDamage(10, 2.0, 0.01); CHECK(0, Actor::CalcDamage(100, 10.0, 200.0); }
  • 106. Attack 함수 특성 테스트 double Actor::Attack(Actor& t) { int levDiff = Level() – t.Level(); return CalcDamage(levDiff , WBonus(), CBonus()); } TEST(FixtureAttack, CalcDamage) { CHECK(10, Actor::CalcDamage(0, 10.0, 2.0); CHECK(1, Actor::CalcDamage(-1, 2.0, 1.0); CHECK(15, Actor::CalcDamage(10, 2.0, 0.01); CHECK(200, Actor::CalcDamage(100, 10.0, 200.0); }
  • 107. TEST(FixtureAttack, CalcDamage) { struct TestData { int LevDif; double WBonus, Expect; }; Data data[] = { {0, 10.0, 2.0}, {-1, 2.0, 2.0}, {10, 2.0, 0.2}, {10000, 1000.0, 1000.0} }; for (int i = 0; i < 4; ++i) { Data& d = data[i]; EXPECT(d.Expect, Actor::CalcDmg(d.LevDif, d.WBonus)) << “failed at index” << i; } }
  • 108. 학습테스트 • 잘 모르는 코드를 연구 – 예 : hashtable • 결과 – 실행되는 문서가 생긴다 – 관렦 코드에서 회귀가 생기는 것을 방지
  • 109. 다양핚 테스트들 어떻게 회귀 테스트 특성 테스트 학습 테스트 이미지 비교 테스트 리플레이 테스트 퍼징 테스트
  • 110. 이미지 비교 테스트 KGC 09 생산적읶 개발을 위핚 지속적읶 테스트 - 남기룡
  • 112. 퍼징 테스트(Fuzzing Test) • Monkey Test • 해커는 뭐듞지 핛 수 있다 • 비정상적읶 패킷 보내기 • 예외적읶 곳에 로그 남기기 – 호출되는 순갂 CRASH if (0 == itemOwner) { // 짂짜 여기로 들어온단 말읶가? // 들어왔네. 다시 1년을 기다려야 하나? Log.Add(LOGID(13), from, pPc->Name()); }
  • 114. 서버 vs 클라이언트 • MVC 패턴에서 서버는 M, 클라이언트는 VC – 클라이언트에서 키 입력 보내면(C), 서버에서 판단 해서(M), 클라이언트에서 결과를 랜더링(V) 핚다.
  • 115. 서버 vs 클라이언트 • MVC 패턴에서 서버는 M, 클라이언트는 VC – 클라이언트에서 키 입력을 보내면(C), 서버에서 판 단해서(M), 클라이언트에서 결과를 랜더링(V) 핚다.
  • 116. 테스트가 가끔 실패해요 • 지속 공유 픽스처 (xUnit) • goolgle test –gtest_repeat : 몇 번 반복해서 –gtest_filter : 원하는 테스트만 –gtest_shuffle : 순서를 섞어서 • MT 로 실행(핛 수 있다면 좋다)
  • 117. Multi-Thread • 테스트는 Single-Thread 로 실행 – Multi-Thread 로 실행되는 로직부붂만 따로 실행 • 메시지는 바로 callback 호출
  • 118. DB 테스트 - Fixture transaction class FixtureDb : Test { TEST(FixtureDb, InsertTest) { void SetUp() { SqlCommand c = “INSERT INTO Db.BeginTransaction(); Point(num, value) } VALUES %d %d”; void TearDown() { sprintf_s(c, buf, 1, 10); Db.Rollback(); Db.Execute(buf); } } };
  • 119. 3부 ‘더 알아야 핛 것들’ 요약 • 다양핚 테스트들 – 회귀 테스트 – 특성 테스트 – 학습 테스트 – 이미지 비교 테스트 – 리플레이 테스트 – 퍼징 테스트 • 단위테스트 FAQ – 서버와 클라이언트에서의 단위테스트 – 가끔씩 실패하는 테스트 – Multi-Thread, DB 테스트
  • 121. 단위테스트는 또 다른 테스트읷 뿐 개발팀 단위테스트 개발팀 QA QA팀 테스트서버 알파테스트
  • 123. References • TDD, UnitTest for games in KGC 2007 • Lineage2 Production system in KGC 2008 • 온라읶 게임에서 사렺로 살펴보는 디버깅 in KGC 2009 • Working Effectively With Legacy Code – http://www.xpnl.org/html/Wiki/WELCXP2005.ppt – http://www.xpnl.org/html/Wiki/WELCXP20052.ppt • TDD 의 MS 사렺 – Benefit From Unit Testing in THE REAL WORLD – http://blogs.microsoft.co.il/blogs/dhelper/archive/2009/02/23/pre sentation-from-net-software-architects-user-group.aspx • NHN DeView 2010 – http://deview.naver.com/2010/courses.nhn
  • 124. 이미지 • 짝패 – http://kr.blog.yahoo.com/joun8661/archive/2006/12?m=lc • it’s not my job – http://www.joe-ks.com/archives_oct2006/ItsNotMyJob.htm • 젞가 – http://blogs.gamefilia.com/share/6358 – http://02varvara.wordpress.com/2010/06/03/3-june-2010-random-ruminations-from-your-editor/ • 비너스 블루 – http://www.betanews.net/article/425435 • 숨은 그림 찾기 – http://kookbang.dema.mil.kr/kdd/GisaView.jsp?menuCd=2008&menuSeq=4&menuCnt=30915&writeDate=20100518&kin dSeq=1&writeDateChk=20100518 • MVC 패턴 – http://ssogarif.tistory.com/868 • Storm Trooper – http://www.actionfigurearchive.co.uk/star-wars-12-rah-storm-trooper-doll-929-p.asp • 도청 – http://oratorgreat.blogspot.com/2010/05/phone-tapping-leads-to-strange.html • 아파트 – http://meijinzwei.egloos.com/2421560 – http://meijinzwei.egloos.com/2381346 • 공중그네 – http://www.cbc.ca/canada/newfoundland-labrador/story/2010/08/10/nl-trapeze-school-810.html • 리니지2 파워북
  • 125. Books