SlideShare a Scribd company logo
Mock Object 소개2011.04.11원종필
TDD? Mock?Q : ……한 경우에 TDD를 어떻게 적용하면 좋을 까요?				A : Mock을 쓰세요.                                  Mock을 쓰면해결 할 수 있어요.Mock은 또 뭐???
목차Mock Object ??
 Mock Object 사용 예
언제 Mock Object를 만들 것 인가?
 Mock 분류
 Test Double 살펴보기
 Mock Framework 사용 유의사항Mock Object ??사진출처 : http://blog.naver.com/yes10001조각하기 쉬운 재료(나무,점토)를 이용해 추후 만들어질 제품의 양을 흉내 낸 모조품모듈의겉모양이 실제 모듈과 비슷하게 보이도록 만든 가짜 객체소프트웨어 개발
Mock Object 사용 예(1/3)UserRegister를 구현, User 암호 저장 기능에 대한 테스트class UserRegister{public:UserRegister() {};	~UserRegister() {};void SavePassword(const std::string& user_id, const std::string& user_pwd)	{user_pwd_table_[user_id] = user_pwd;	}std::string GetPassword(const std::string& user_id)	{		std::map<std::string, std::string>::iterator it = user_pwd_table_.find(user_id);		assert(it != user_pwd_table_.end());		return it->second;	}private:	std::map<std::string, std::string> user_pwd_table_;};TEST(PasswordTest, password_ciper_test){UserRegister* user_register = new UserRegister();	std::string user_id = "aether";	std::string user_pwd = "potato";user_register->SavePassword(user_id, user_pwd);	EXPECT_EQ(user_pwd, user_register->GetPassword(user_id));}테스트성공!!
Mock Object 사용 예(2/3)요구 사항 – 사용자 암호는 반드시 암호화한 다음에 저장해야 한다class Cipher{public:	Cipher();	~Cipher();	virtual std::string Encryption(const std::string& source)=0;	virtual std::string Decryption(const std::string& source)=0;};MD5 기반으로다른 개발자가독립적으로 구현하기로..TEST(PasswordTest, password_ciper_test){UserRegister* user_register = new UserRegister();// Ciper* ciper = ... 이거 만들어주면되는데..	std::string user_id = "aether";	std::string user_pwd = "potato";user_register->SavePassword(user_id, cipher->Encryption(user_pwd));	std::string decripted_pwd = cipher->Decryption(user_register->GetPassword(user_id));	EXPECT_EQ(user_pwd, decripted_pwd);}테스트 코드를 통과시켜야 하는데............... 다른 개발자가 MD5를 기반으로 Cipher를 만들어 줄 때까지 기다려야 하는가?
Mock Object 사용 예(3/3)MD5Cipher처럼 보이는 객체를 만들어서 사용하자.class MockMD5Cipher : public Cipher{public:	MockMD5Cipher()	{};	~MockMD5Cipher()	{};virtual std::string Encryption(const std::string& source) 	{ 		return "8ee2027983915ec78acc45027d874316“;	}	virtual std::string Decryption(const std::string& source) 	{ return "potato“; }};TEST(PasswordTest, password_ciper_test){UserRegister* user_register = new UserRegister();Cipher* cipher = new MockMD5Cipher();	std::string user_id = "aether";	std::string user_pwd = "potato";user_register->SavePassword(user_id, cipher->Encryption(user_pwd));	std::string decripted_pwd = cipher->Decryption(user_register->GetPassword(user_id));	EXPECT_EQ(user_pwd, decripted_pwd);}MockMD5Cipher의 구현자체는 임시적이겠지만, 정말 구현하려고 하는 SavePassword기능을 테스트 케이스로 만들기에는 충분한 코드이다.
언제 Mock Object를 만들 것인가?모듈이 가진 의존성이 근본적인 원인모듈이 필요로 하는 의존성은테스트 작성을 어렵게 만든다.
언제 Mock Object를 만들 것인가?1. 테스트 작성을 위한 환경 구축이 어려울 때환경 구축을 위한 작업시간이 많이 필요할 때
사용하고 있는 DB와 다른 DB를 설치해야만 테스트가 가능한 경우
특정 모듈을 아직 갖고 있지 않아서 테스트 환경을 구축하지 못할 때
아직 모듈 개발이 완료되지 않았거나 심각한 버그가 있는 경우2. 테스트가 특정 경우나 순간에 의존적일 때네트워크 지연에 따른 예외처리를 하고자 하는 경우
테스트 할 때마다 원하는 만큼의 네트워크 지연을 만들기 위해수동적으로 환경을 조성하기에는 노력이 많이 든다.Mock에 대한 분류테스트 대역(Test Double)오리지널 객체를 사용해서 테스트를 진행하기가 어려운 경우이를 대신해서 테스트를 진행할 수 있도록 만들어 주는 객체
xUnit Test Patterns의 저자 제라드메스자로스(Gerard Meszaros)가용어를 만들고, 분류하여 사용하기 시작함.
많은 개발자들이 좀 더 포괄적이고 보편적인 개념으로   Mock이라는 단어를 사용하고있지만, 분류법은 알아둘 만함.Mock에 대한 분류테스트 대역(Test Double)의 종류제라드메스자로스(Gerard Meszaros)
테스트 대역(Test Double)하나씩 살펴보기
예제 설명class Item{public:	Item()	{};virtual ~Item()	{};virtual std::string GetName() = 0;	virtual boolIsValid() = 0;	virtual boolIsAppliable(Actor* actor) = 0;	virtual intGetPrice() = 0;	virtual intGetDiscountPrice() = 0;};Actor에 Item 추가 기능 구현 - Item은 인터페이스 논의만 된 상태class Actor{public:	Actor(const std::string actor_name)	{};	~Actor()	{};void AddItem(Item* item) { item_list_.push_back(item); }intGetTotalItemCount() { return item_list_.size(); }private:	std::list<Item*> item_list_;};TEST(TestDouble, test_double_dummy_object){	Actor* actor = new Actor("Warrior");		EXPECT_EQ(0, actor->GetTotalItemCount());//Item* item = 	actor->AddItem(item);	EXPECT_EQ(1, actor->GetTotalItemCount());}
더미 객체(Dummy Object)더미 객체는 말 그대로 모조품, 단순한 껍데기에 해당한다class DummyItem : public Item{public:DummyItem()  {};	~DummyItem() {};	virtual std::string GetName() { 		assert(false); 		return ""; }	virtual boolIsValid() { 		assert(false); 		return false; }	virtual boolIsAppliable(Actor* actor) { 		assert(false); 		return false; }	virtual intGetPrice() { 		assert(false); 		return -1; }	virtual intGetDiscountPrice() { 		assert(false); 		return -1; }};TEST(TestDouble, test_double_dummy_object){	Actor* actor = new Actor("Warrior");		EXPECT_EQ(0, actor->GetTotalItemCount());	Item* item = new DummyItem();	actor->AddItem(item);	EXPECT_EQ(1, actor->GetTotalItemCount());} 단지 인스턴스화 된 객체가 필요할 뿐객체의 기능까지 필요하지 않은 경우 사용
더미 객체의 메소드가 호출 됐을 때의 동작은 보장하지 않는다.
테스트 과정에서 메소드 호출이 필요한 경우더미보다 좀더 발전된 객체를 사용해야 한다테스트 스텁(Test Stub)더미 객체가실제로 동작하는 것처럼 보이게 만들어 놓은 객체class StubItem : public Item{public:StubItem()  {};	~StubItem() {};	virtual std::string GetName() { 				return "체력만땅물약"; }	virtual boolIsValid() { 				return true; }	virtual boolIsAppliable(Actor* actor) { 				return true; }	virtual intGetPrice() 	{ 				return 500; }	virtual intGetDiscountPrice() { 				return 200; }};TEST(TestDouble, test_double_stub_object){	Actor* actor = new Actor("Warrior");		EXPECT_EQ(0, actor->GetTotalItemCount());Item* item = new StubItem();	actor->AddItem(item);Item* last_added_item = 		actor->GetLastAddedItem();	EXPECT_EQ(500, last_added_item->GetPrice());	EXPECT_EQ("체력만땅물약", last_added_item->GetName());} 객체의 특정 상태를 가정해서 만들어 놓은단순 구현체이다.
하드 코딩되어 있기 때문에 로직이들어가는 부분은 테스트 할 수 없다가짜 객체(Fake Object)여러 개의 인스턴스를 대표할 수 있는 경우이거나, 좀더 복잡한 구현이 들어가 있는 객체를 지칭한다class FakeObjectItem : public Item{FakeObjectItem()  {appliable_state_list_.push_back(Actor::kDeath);appliable_state_list_.push_back(Actor::kZombie);};virtual boolIsAppliable(Actor* actor) { 		Actor::ActorStateactor_state = actor->GetActorState();			std::list<Actor::ActorState>::iterator it = 	std::find(appliable_state_list_.begin(),appliable_state_list_.end(), actor_state);	if(it != appliable_state_list_.end()){		return true;}	return false; }bool Actor::UseItem(Item* item){if(item->IsAppliable(this) == true){		return true;}	return false;}TEST(TestDouble, test_double_fake_object){	Actor* actor = new Actor("Warrior");		EXPECT_EQ(0, actor->GetTotalItemCount());actor->SetActorState(Actor::kWalk);	Item* item = new StubItem();	EXPECT_EQ(true, actor->UseItem(item));	Item* fake_item = new FakeObjectItem();	EXPECT_EQ(false, actor->UseItem(fake_item));actor->SetActorState(Actor::kDeath);	EXPECT_EQ(true, actor->UseItem(fake_item));} 가짜 객체를 지나치게 구현하면, 가짜 객체 자체를 테스트 해야 할 정도로복잡해질 수도 있다.
적절한 수준에서 구현을 접고, 필요 시  Mock 프레임워크를 사용해라.테스트 스파이(Test Spy)특정메소드의 정상 호출 여부를 확인할 목적으로 구현 감시대상이 되는 것은무엇이든 기록한다

More Related Content

PDF
자바 테스트 자동화
PDF
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
PPTX
Tdd 4장
PPTX
프론트엔드스터디 E03 - Javascript intro.
PDF
구글테스트
PDF
시작하자 단위테스트
PPTX
프론트엔드스터디 E04 js function
PDF
KGC2010 - 낡은 코드에 단위테스트 넣기
자바 테스트 자동화
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
Tdd 4장
프론트엔드스터디 E03 - Javascript intro.
구글테스트
시작하자 단위테스트
프론트엔드스터디 E04 js function
KGC2010 - 낡은 코드에 단위테스트 넣기

What's hot (20)

PDF
Javascript
PDF
Java 변수자료형
PDF
Python 테스트 시작하기
PPTX
Jdk(java) 7 - 5. invoke-dynamic
PPTX
10장 결과 검증
PPTX
프론트엔드스터디 E05 js closure oop
PDF
[Main Session] 미래의 Java 미리보기 - 앰버와 발할라 프로젝트를 중심으로
PDF
Effective unit testing ch3. 테스트더블
PPT
헷갈리는 자바스크립트 정리
PPTX
3-1. css
PDF
Python Unittest
DOCX
Javascript 완벽 가이드 정리
PPTX
자바스크립트 기초문법~함수기초
PDF
Java lambda
PPTX
0.javascript기본(~3일차내)
PDF
Java class
PPTX
JUnit 지원 라이브러리 소개
PPTX
C++ 프로젝트에 단위 테스트 도입하기
PPTX
4-1. javascript
PDF
Javascript 교육자료 pdf
Javascript
Java 변수자료형
Python 테스트 시작하기
Jdk(java) 7 - 5. invoke-dynamic
10장 결과 검증
프론트엔드스터디 E05 js closure oop
[Main Session] 미래의 Java 미리보기 - 앰버와 발할라 프로젝트를 중심으로
Effective unit testing ch3. 테스트더블
헷갈리는 자바스크립트 정리
3-1. css
Python Unittest
Javascript 완벽 가이드 정리
자바스크립트 기초문법~함수기초
Java lambda
0.javascript기본(~3일차내)
Java class
JUnit 지원 라이브러리 소개
C++ 프로젝트에 단위 테스트 도입하기
4-1. javascript
Javascript 교육자료 pdf
Ad

Similar to [2011 04 11]mock_object 소개 (20)

PDF
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
PPT
Agile Test Driven Development For Games What, Why, And How
PPT
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
PDF
Spring Boot 2
PDF
[IT기술칼럼#2] 고급자바스크립트 for AngularJS, React_고급자바스크립트,AngularJS,React전문교육학원
PPT
Refactoring - Chapter 8.2
PPTX
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
PPTX
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
PPTX
Naver api for android
PDF
Android UI Test (Espresso/Kakao)
PDF
Io t에서의 소프트웨어단위테스트_접근사례
PDF
W14 chap13
PPTX
자바스크립트 패턴 3장
PPT
Boost라이브러리의내부구조 20151111 서진택
PDF
TDD&Refactoring Day 03: TDD
PPTX
Angular2 가기전 Type script소개
PDF
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
PPTX
Design patterns
 
PPTX
120908 레거시코드활용전략 4장5장
PPTX
Droid knights android test @Droid Knights 2018
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
Agile Test Driven Development For Games What, Why, And How
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Spring Boot 2
[IT기술칼럼#2] 고급자바스크립트 for AngularJS, React_고급자바스크립트,AngularJS,React전문교육학원
Refactoring - Chapter 8.2
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
Naver api for android
Android UI Test (Espresso/Kakao)
Io t에서의 소프트웨어단위테스트_접근사례
W14 chap13
자바스크립트 패턴 3장
Boost라이브러리의내부구조 20151111 서진택
TDD&Refactoring Day 03: TDD
Angular2 가기전 Type script소개
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
Design patterns
 
120908 레거시코드활용전략 4장5장
Droid knights android test @Droid Knights 2018
Ad

More from Jong Pil Won (14)

PPTX
[2012 11 12]애자일 회고
PPTX
[2012 03 17]clean_code 14장 점진적개선
PPT
파이썬3프로그래밍 2장 2003
PPTX
[2012 02 03]clean_code 5장
PPTX
[2012 02 03]clean_code 4장
PPTX
[2012 01 28]cleancode 3장
PPTX
[2012 01 28]cleancode 1장
PPTX
[2011 05 21] 4장 제어
PPTX
[2011 05 21] 4장 제어
PPTX
[2011 05 21] 4장 제어
PPTX
[2011 04 30]python-3장
PPTX
Tdd 마무리
PPTX
Tdd 실습&나머지
PPTX
10장 동기부여와훈련 경험
[2012 11 12]애자일 회고
[2012 03 17]clean_code 14장 점진적개선
파이썬3프로그래밍 2장 2003
[2012 02 03]clean_code 5장
[2012 02 03]clean_code 4장
[2012 01 28]cleancode 3장
[2012 01 28]cleancode 1장
[2011 05 21] 4장 제어
[2011 05 21] 4장 제어
[2011 05 21] 4장 제어
[2011 04 30]python-3장
Tdd 마무리
Tdd 실습&나머지
10장 동기부여와훈련 경험

[2011 04 11]mock_object 소개

  • 2. TDD? Mock?Q : ……한 경우에 TDD를 어떻게 적용하면 좋을 까요? A : Mock을 쓰세요. Mock을 쓰면해결 할 수 있어요.Mock은 또 뭐???
  • 4. Mock Object 사용 예
  • 5. 언제 Mock Object를 만들 것 인가?
  • 7. Test Double 살펴보기
  • 8. Mock Framework 사용 유의사항Mock Object ??사진출처 : http://blog.naver.com/yes10001조각하기 쉬운 재료(나무,점토)를 이용해 추후 만들어질 제품의 양을 흉내 낸 모조품모듈의겉모양이 실제 모듈과 비슷하게 보이도록 만든 가짜 객체소프트웨어 개발
  • 9. Mock Object 사용 예(1/3)UserRegister를 구현, User 암호 저장 기능에 대한 테스트class UserRegister{public:UserRegister() {}; ~UserRegister() {};void SavePassword(const std::string& user_id, const std::string& user_pwd) {user_pwd_table_[user_id] = user_pwd; }std::string GetPassword(const std::string& user_id) { std::map<std::string, std::string>::iterator it = user_pwd_table_.find(user_id); assert(it != user_pwd_table_.end()); return it->second; }private: std::map<std::string, std::string> user_pwd_table_;};TEST(PasswordTest, password_ciper_test){UserRegister* user_register = new UserRegister(); std::string user_id = "aether"; std::string user_pwd = "potato";user_register->SavePassword(user_id, user_pwd); EXPECT_EQ(user_pwd, user_register->GetPassword(user_id));}테스트성공!!
  • 10. Mock Object 사용 예(2/3)요구 사항 – 사용자 암호는 반드시 암호화한 다음에 저장해야 한다class Cipher{public: Cipher(); ~Cipher(); virtual std::string Encryption(const std::string& source)=0; virtual std::string Decryption(const std::string& source)=0;};MD5 기반으로다른 개발자가독립적으로 구현하기로..TEST(PasswordTest, password_ciper_test){UserRegister* user_register = new UserRegister();// Ciper* ciper = ... 이거 만들어주면되는데.. std::string user_id = "aether"; std::string user_pwd = "potato";user_register->SavePassword(user_id, cipher->Encryption(user_pwd)); std::string decripted_pwd = cipher->Decryption(user_register->GetPassword(user_id)); EXPECT_EQ(user_pwd, decripted_pwd);}테스트 코드를 통과시켜야 하는데............... 다른 개발자가 MD5를 기반으로 Cipher를 만들어 줄 때까지 기다려야 하는가?
  • 11. Mock Object 사용 예(3/3)MD5Cipher처럼 보이는 객체를 만들어서 사용하자.class MockMD5Cipher : public Cipher{public: MockMD5Cipher() {}; ~MockMD5Cipher() {};virtual std::string Encryption(const std::string& source) { return "8ee2027983915ec78acc45027d874316“; } virtual std::string Decryption(const std::string& source) { return "potato“; }};TEST(PasswordTest, password_ciper_test){UserRegister* user_register = new UserRegister();Cipher* cipher = new MockMD5Cipher(); std::string user_id = "aether"; std::string user_pwd = "potato";user_register->SavePassword(user_id, cipher->Encryption(user_pwd)); std::string decripted_pwd = cipher->Decryption(user_register->GetPassword(user_id)); EXPECT_EQ(user_pwd, decripted_pwd);}MockMD5Cipher의 구현자체는 임시적이겠지만, 정말 구현하려고 하는 SavePassword기능을 테스트 케이스로 만들기에는 충분한 코드이다.
  • 12. 언제 Mock Object를 만들 것인가?모듈이 가진 의존성이 근본적인 원인모듈이 필요로 하는 의존성은테스트 작성을 어렵게 만든다.
  • 13. 언제 Mock Object를 만들 것인가?1. 테스트 작성을 위한 환경 구축이 어려울 때환경 구축을 위한 작업시간이 많이 필요할 때
  • 14. 사용하고 있는 DB와 다른 DB를 설치해야만 테스트가 가능한 경우
  • 15. 특정 모듈을 아직 갖고 있지 않아서 테스트 환경을 구축하지 못할 때
  • 16. 아직 모듈 개발이 완료되지 않았거나 심각한 버그가 있는 경우2. 테스트가 특정 경우나 순간에 의존적일 때네트워크 지연에 따른 예외처리를 하고자 하는 경우
  • 17. 테스트 할 때마다 원하는 만큼의 네트워크 지연을 만들기 위해수동적으로 환경을 조성하기에는 노력이 많이 든다.Mock에 대한 분류테스트 대역(Test Double)오리지널 객체를 사용해서 테스트를 진행하기가 어려운 경우이를 대신해서 테스트를 진행할 수 있도록 만들어 주는 객체
  • 18. xUnit Test Patterns의 저자 제라드메스자로스(Gerard Meszaros)가용어를 만들고, 분류하여 사용하기 시작함.
  • 19. 많은 개발자들이 좀 더 포괄적이고 보편적인 개념으로 Mock이라는 단어를 사용하고있지만, 분류법은 알아둘 만함.Mock에 대한 분류테스트 대역(Test Double)의 종류제라드메스자로스(Gerard Meszaros)
  • 21. 예제 설명class Item{public: Item() {};virtual ~Item() {};virtual std::string GetName() = 0; virtual boolIsValid() = 0; virtual boolIsAppliable(Actor* actor) = 0; virtual intGetPrice() = 0; virtual intGetDiscountPrice() = 0;};Actor에 Item 추가 기능 구현 - Item은 인터페이스 논의만 된 상태class Actor{public: Actor(const std::string actor_name) {}; ~Actor() {};void AddItem(Item* item) { item_list_.push_back(item); }intGetTotalItemCount() { return item_list_.size(); }private: std::list<Item*> item_list_;};TEST(TestDouble, test_double_dummy_object){ Actor* actor = new Actor("Warrior"); EXPECT_EQ(0, actor->GetTotalItemCount());//Item* item = actor->AddItem(item); EXPECT_EQ(1, actor->GetTotalItemCount());}
  • 22. 더미 객체(Dummy Object)더미 객체는 말 그대로 모조품, 단순한 껍데기에 해당한다class DummyItem : public Item{public:DummyItem() {}; ~DummyItem() {}; virtual std::string GetName() { assert(false); return ""; } virtual boolIsValid() { assert(false); return false; } virtual boolIsAppliable(Actor* actor) { assert(false); return false; } virtual intGetPrice() { assert(false); return -1; } virtual intGetDiscountPrice() { assert(false); return -1; }};TEST(TestDouble, test_double_dummy_object){ Actor* actor = new Actor("Warrior"); EXPECT_EQ(0, actor->GetTotalItemCount()); Item* item = new DummyItem(); actor->AddItem(item); EXPECT_EQ(1, actor->GetTotalItemCount());} 단지 인스턴스화 된 객체가 필요할 뿐객체의 기능까지 필요하지 않은 경우 사용
  • 23. 더미 객체의 메소드가 호출 됐을 때의 동작은 보장하지 않는다.
  • 24. 테스트 과정에서 메소드 호출이 필요한 경우더미보다 좀더 발전된 객체를 사용해야 한다테스트 스텁(Test Stub)더미 객체가실제로 동작하는 것처럼 보이게 만들어 놓은 객체class StubItem : public Item{public:StubItem() {}; ~StubItem() {}; virtual std::string GetName() { return "체력만땅물약"; } virtual boolIsValid() { return true; } virtual boolIsAppliable(Actor* actor) { return true; } virtual intGetPrice() { return 500; } virtual intGetDiscountPrice() { return 200; }};TEST(TestDouble, test_double_stub_object){ Actor* actor = new Actor("Warrior"); EXPECT_EQ(0, actor->GetTotalItemCount());Item* item = new StubItem(); actor->AddItem(item);Item* last_added_item = actor->GetLastAddedItem(); EXPECT_EQ(500, last_added_item->GetPrice()); EXPECT_EQ("체력만땅물약", last_added_item->GetName());} 객체의 특정 상태를 가정해서 만들어 놓은단순 구현체이다.
  • 25. 하드 코딩되어 있기 때문에 로직이들어가는 부분은 테스트 할 수 없다가짜 객체(Fake Object)여러 개의 인스턴스를 대표할 수 있는 경우이거나, 좀더 복잡한 구현이 들어가 있는 객체를 지칭한다class FakeObjectItem : public Item{FakeObjectItem() {appliable_state_list_.push_back(Actor::kDeath);appliable_state_list_.push_back(Actor::kZombie);};virtual boolIsAppliable(Actor* actor) { Actor::ActorStateactor_state = actor->GetActorState(); std::list<Actor::ActorState>::iterator it = std::find(appliable_state_list_.begin(),appliable_state_list_.end(), actor_state); if(it != appliable_state_list_.end()){ return true;} return false; }bool Actor::UseItem(Item* item){if(item->IsAppliable(this) == true){ return true;} return false;}TEST(TestDouble, test_double_fake_object){ Actor* actor = new Actor("Warrior"); EXPECT_EQ(0, actor->GetTotalItemCount());actor->SetActorState(Actor::kWalk); Item* item = new StubItem(); EXPECT_EQ(true, actor->UseItem(item)); Item* fake_item = new FakeObjectItem(); EXPECT_EQ(false, actor->UseItem(fake_item));actor->SetActorState(Actor::kDeath); EXPECT_EQ(true, actor->UseItem(fake_item));} 가짜 객체를 지나치게 구현하면, 가짜 객체 자체를 테스트 해야 할 정도로복잡해질 수도 있다.
  • 26. 적절한 수준에서 구현을 접고, 필요 시 Mock 프레임워크를 사용해라.테스트 스파이(Test Spy)특정메소드의 정상 호출 여부를 확인할 목적으로 구현 감시대상이 되는 것은무엇이든 기록한다
  • 27. 아주 특수한 경우를 제외하고 잘 쓰이지않는다. 필요한 경우 Mock 프레임워크를이용하는 것이 더 간편함.
  • 28. Mock 프레임워크에서대부분 기본 제공한다.class SpyItem : public Item{SpyItem() {appliable_state_list_.push_back(Actor::kDeath);appliable_state_list_.push_back(Actor::kZombie);};virtual boolIsAppliable(Actor* actor) { Actor::ActorStateactor_state = actor->GetActorState(); std::list<Actor::ActorState>::iterator it = std::find(appliable_state_list_.begin(),appliable_state_list_.end(), actor_state);is_appliable_call_count ++; if(it != appliable_state_list_.end()){ … }IntGetAppliableCallCount() { return is_appliable_call_count ++; }TEST(TestDouble, test_double_test_spy){ Actor* actor = new Actor("Warrior"); EXPECT_EQ(0, actor->GetTotalItemCount()); actor->SetActorState(Actor::kDeath); Item* item = new SpyItem(); EXPECT_EQ(true, actor->UseItem(item));intmethod_call_count = ((SpyItem*)item)->GetAppliableCallCount(); EXPECT_EQ(1, method_call_count);}
  • 29. Mock 객체(Mock Object)행위 기반 테스트 Vs 상태 기반 테스트상태 기반 테스트
  • 30. 테스트 대상 클래스의 메소드를 호출하고, 그 결과값과예상 값을 비교하는 방법입력AMethodA??결과 값예상 값
  • 31. Mock 객체(Mock Object)행위 기반 테스트 Vs 상태 기반 테스트 행위 기반 테스트
  • 32. 올바른 로직 수행 판단의 근거로 특정한 동작의 수행여부를이용한다.
  • 33. 리턴 값을 확인하는 것만으로는 예상대로 동작했음을보증하기 어려운 경우에 사용한다입력A입력B실행MethodAMethodBMethodAMethodB
  • 34. Mock 객체(Mock Object)Mock 객체는행위를 검증하기 위해 사용되는 객체 수동으로 만들 수도 있지만, 대부분 Mock 프레임워크를 이용
  • 35. 대표적인 C++ Mock 프레임워크
  • 36. Google MockTEST(TestDouble, test_double_gmock_test){ Actor* actor = new Actor("Warrior"); EXPECT_EQ(0, actor->GetTotalItemCount());MockItem* item = new MockItem(); EXPECT_CALL(*item, IsAppliable(actor)) .Times(::testing::AtLeast(2)) .WillOnce(::testing::Return(true)) .WillOnce(::testing::Return(false)); EXPECT_EQ(true, actor->UseItem(item)); EXPECT_EQ(false, actor->UseItem(item));}classMockItem: public Item{public:MockItem() {}; virtual ~MockItem() {}; MOCK_METHOD0(GetName, std::string()); MOCK_METHOD0(IsValid, bool()); MOCK_METHOD1(IsAppliable, bool(Actor*)); MOCK_METHOD0(GetPrice, int());};
  • 37. Googlemock(code.google.com/p/googlemock)jMock, EasyMock, Hamcrest의 영향을 받아만들어진 C++ Mocking Framework
  • 38. googlemock자료는이곳에 있는 게 거의 전부Test Double의 연속성http://msdn.microsoft.com/ko-kr/magazine/cc163358.aspx
  • 39. Mock 사용시 유의사항1. Mock 프레임워크가 정말 필요한지 잘 따져본다Mock을 사용하는 것 자체가 목적이 되면 안된다. Mock 객체가 필요한부분이 나오는 것이 아니라, Mock 객체가 적용될 수 있는 부분을 찾으려고애쓰는 현상은 올바르지 못하다
  • 40. 한번 Mock 프레임워크를 사용하면 해당 테스트 케이스를유지하는데 지속적인 비용이 발생한다.
  • 41. 가능하다면 설계를 바꿔서라도 Mock이 필요없는 의존성 적은구조를 만들어라. 그것이 Mock 객체를 쓰기 위해 노력 하는 것 보다 낫다2.Mock은 Mock일 뿐이다. Mock 객체를 사용해 아무리 잘 동작하게 만들었어도, 실제 객체에서도잘 동작하리라는 보장은 없다 Mock객체는 실제 객체로 대체되어 테스트해야하는 시점이 온다.
  • 42. 초반부터 실제 객체를 사용할 수 있고, 그 비용이 크지 않다면 Mock 객체를 사용하지 말자.참고 자료 고품질 쾌속 개발을 위한 TDD실천법과 도구
  • 44. C++ 프로젝트에 단위 테스트 도입하기(온라인서버프로그래머 세미나 발표자료)Q / A
  • 45. END