테스트 더블(Test Double)의 종류와 차이점?

원문 : http://googletesting.blogspot.kr/2013/07/testing-on-toilet-know-your-test-doubles.html

테스트 더블이란 테스트시에 실제 객체를 대신 할 수 있는 객체를 의미 합니다. (여기서 ‘더블’이란 말의 유래는 영화에서 스턴트 대역[stunt double]을 생각하시면 될 듯 하네요.)

테스트 더블을 Mock Object 로 흔히들 알고 있는데요. 그 종류로는 Stub, Mock, Fake Object 등이 있습니다. 각각 다른 용도를 가지고 있기 때문에 어떤 테스트 더블을 언제 써야할지 알기 위해서 서로 구분하는 것은 중요합니다.

각 종류에 대해 간단히 살펴보면,

Stub은 로직이 없고 단지 원하는 값을 반환합니다. 테스트시에 “이 객체는 무조건 이 값을 반환한다”고 가정할 경우 사용할 수 있습니다. Stub은 보통 작성하기 쉽지만 불필요한 boilerplate 코드를 줄이기 위해서 Mocking Framework을 이용하는게 편합니다.

아래는 예제 코드입니다.

// Mocking Framework에 의해 생성 된 Stub 객체를 전달
AccessManager accessManager = new AccessManager(stubAuthenticationService):

// 사용자는 AutheniticationService가 false를 반환할 때 접근 할 수 없어야 한다.
when(stubAuthenticationService.isAuthenticated(USER_ID)).thenReturn(false);
assertFalse(accessManager.userHasAccess(USER_ID));

// 사용자는 AutheniticationService가 true를 반환할 때 접근 할 수 있어야 한다.
when(stubAuthenticationService.isAuthenticated(USER_ID)).thenReturn(true);
assertTrue(accessManager.userHasAccess(USER_ID));

[코드1] Stub 객체를 생성하고 해당 객체의 결과 값을 Mocking 한 후 단정문으로 확인하는 테스트 코드

Mock은 “어떤 메소드가 호출 될 것이다”라는 행위에 대한 예상을 가지고 있습니다. 만약 그 예상대로 메소드가 호출 되지 않을 경우 테스트는 실패합니다. 이렇듯 Mock은 객체 사이의 행위(interaction)를 테스트하기 위해 사용합니다. 식별 할 수 있는 상태 변경이 없거나 반환 값으로 확인 할 수 없는 경우에 유용합니다. 예를 들면 어떤 코드가 디스크에서 read 작업을 하는데 하나 이상의 디스크에서 read 작업을 수행하지 않도록 하려는 경우, read 작업을 수행하는 메소드가 한번만 호출 되었는지 검증하기 위해 Mock을 사용할 수 있습니다.

아래는 예제 코드입니다.

// Mocking Framework에 의해 생성 된 Stub 객체를 전달
AccessManager accessManager = new AccessManager(mockAuthenticationService):
accessManager.userHasAccess(USER_ID);

// 만약 accessManager.userHasAccess(USER_ID) 메소드에서
// mockAuthenticationService.isAuthenticated(USER_ID)가 호출되지 않았거나 한번 이상 호출되었다면 테스트가 실패한다.
verify(mockAuthenticationService).isAuthenticated(USER_ID);

[코드2] Mock 객체를 생성하고 행위에 대한 테스트를 검증하는 코드

Fake는 Mocking Framework를 사용하지 않습니다. 실제 구현 처럼 동작하게끔 간단히 구현합니다. Fake는 테스트 수행시 실제 구현 객체가 너무 느리거나 네트워크를 통해 무언가 수행해야하거나 등의 이유로 이용 할 수 없을 경우 사용 할 수 있습니다. Fake는 대체로 실제 구현 객체를 개발한 사람이나 팀에 의해 생성되거나 유지보수 되기 때문에 직접 작성할 필요는 없습니다. (*역주:보통 익명 클래스로 특정 메소드를 간단히 Overriding 해서 이용하기도 합니다.)

// Fake를 생성하는 것은 쉽고 빠름
AuthenticationService fakeAuthenticationService = new FakeAuthenticationService();
AccessManager accessManager = new AccessManager(fakeAuthenticationService):

// AuthenticationService에서 사용자에 대해 모를 경우 접근할 수 없어야 한다.
// 내부적으로 accessManager.userHasAccess() 메소드 안에서 AuthenticationService Fake Object를 통해 접근여부 확인함
assertFalse(accessManager.userHasAccess(USER_ID));

// 사용자는 AuthenticationService에 추가한 이후에 접근 할 수 있어야 한다.
fakeAuthenticationService.addAuthenticatedUser(USER_ID);
assertTrue(accessManager.userHasAccess(USER_ID));

[코드3] Fake Object를 생성하고 테스트하는 방법

더 많은 정보는 다음 사이트에서,
http://xunitpatterns.com/Test%20Double%20Patterns.html
http://martinfowler.com/articles/mocksArentStubs.html

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.