Fakes
, Stubs
, Mocks
로 분류할 수 있다.public interface MemberRepository extends JpaRepository<Long, Member> {
Optional<Member> findByName(String name);
}
public class FakeMemberRepository implements MemberRepository {
List<Member> members = new ArrayList<>();
public FakeAccountRepository() {
this.members.add(new Member("bossdog", "bsdg@gmail.com");
this.members.add(new Member("pobi", "javajigi@gmail.com");
}
@Override
Member save(Member member) {
members.add(member);
return member;
}
@Override
Optional<Member> findByName(String name) {
return members.stream()
.filter(m -> m.isName(name))
.findFirst();
}
}
@ExtendWith(MockitoExtension.class)
public class MemberServiceTest {
@Mock private MemberRepository; // 레파지토리를 Stubbing할 객체로 지정한다.
@Test
public void saveTest() {
// given
Member member = new Member("bossdog", "bsdg@gmail.com"); // 반환 예정 상태 미리 지정
when(memberRepository.save(any())).thenReturn(member); // stubbing!
// when
Member member = memberService.save(member);
// then
assertThat(member.getName()).isEqualTo("bossdog");
}
}
@Test
public void mockTest() {
Member member = mock(Member.class);
Team team = new Team(member);
team.win();
verify(member).increasePoint();
}
Test Double인 Fakes, Stubs, Mocks에 대해 간단히 그 차이를 살펴보았다. 결과적으로 말하면 세 가지 방식은 처음 문제였던 테스트 격리에 관해서 실제 데이터 베이스를 사용하지 않기 때문에 모두 테스트 격리에 도움이 되는 방법들이라고 할 수 있을 것이다.
어떤 방식이 가장 효과적이냐고 묻지는 말자.
앞서 살펴본 Test Double들은 존재하는 그 목적이 다르기 때문에 상황에 따라서 가장 적절하고 효과적인 방식을 선택해서 사용하는 것이 현명할 것이다.
웹 애플리케이션 아키텍처는 보통 계층구조로 되어있다. Test Double을 적절히 잘 사용한다면, 계층구조의 단점을 피해 TDD로 개발하는데에도 많은 도움이 될 것이다.
그러나 분명 Mock Test는 단점도 있다. 테스트를 통과했다고해서 실제 운영 조건에서도 정상적으로 기능이 동작하리라 확신할 수는 없다는 것이다. 이를 보완할 수 있도록 인수테스트나, 통합테스트를 추가로 작성하는 것이 좋다고 생각한다.
Test Doubles — Fakes, Mocks and Stubs.TestDouble - martin fowlerUnit Testing: Fakes, Mocks and Stubs