반응형
Mockito
- Mockito란?
- 복잡하게 얽혀있는 객체들의 의존성 때문에 원하는 비즈니스 로직에 대한 테스트를 작성하기 힘들다
- 이때 의존성을 가지는 객체들을 가짜 객체를 만들어 테스트할 수 있는데 이런 객체를 Mock 객체라고 한다
- Mockito는 이름에서도 알 수 있다시피 관리가 어려운 Mock 객체를 손쉽게 사용하도록 지원해주는 프레임워크이다.
- 생성 방식
- mock method
// JUnit 5 import static org.mockito.Mockito.mock; public class MemberServiceTest2 { private MemberRepository memberRepository; private MemberService memberService; @BeforeEach void setUpTest() { memberRepository = mock(MemberRepository.class); memberService = new MemberService(memberRepository); } ... }
- org.mockito.Mockito.mock를 통해 해당 클래스에 맞는 Mock 객체를 생성할 수 있다
- @Mock 어노테이션
@Mock 어노테이션을 이용해 Mock 객체를 생성하고, @InjectMocks를 이용해 해당 클래스로 의존성 주입을 할 수 있다import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; @ExtendWith(MockitoExtension.class) class MemberServiceTest { @Mock MemberRepository memberRepository; @InjectMocks MemberService memberService; ... }
- mock method
- 사용 방법
- 생성된 Mock 객체의 사용 방법은 간단하다
- when 메서드를 통해 원하는 동작을 미리 정하고 이를 기반으로 테스트할 수 있다.
- 또한 호출 등이 정확히 됐는지 확인할 수 있는 verify 메서드를 지원한다
// JUnit5 + AssertJ // given Mockito.when(memberRepository.findAll()) .thenReturn(List.of(Member.builder().name("블로그주인1").age(30).address("구로구").build(), Member.builder().name("블로그주인2").age(31).address("광진구").build())); // when List<MemberResponse> actual = memberService.getMembers(); // then assertThat(actual).isNotEmpty(); assertThat(actual).extracting("name","age","address") .contains(tuple("블로그주인1",30,"구로구") , tuple("블로그주인2",31,"광진구")); Mockito.verify(memberRepository).findAll();
- verify methd는 두번째 인자로 VerificationMode를 갖게되는데 호출횟수(times, never, atleast)를 지정할 수 있다
BDDMockito
- Behavior-Driven Development Mockito 로 풀어쓸 수 있다
- BDD는 즉 행위 주도 개발을 말한다.
- 테스트 대상의 상태의 변화를 테스트하는 것이고, 시나리오를 기반으로 테스트하는 패턴을 권장한다.
- BDD 권장 행동 패턴은 Given, When, Then 로 나눠진다
- 음 위의 내용은 이해했는데 그럼 Mockito랑 무슨 차이지?
- 위에서 소개했던 Mockito의 사용 방법 예시를 보면 뭔가 어색한(?) 곳을 찾을 수 있다
// Mocito @ExtendWith(MockitoExtension.class) class MemberServiceTest { @Mock MemberRepository memberRepository; @InjectMocks MemberService memberService; @Test void test() { // given Mockito.when(memberRepository.method).... // when // then Mockito.verify(memberRepository).... } }
- 혹시.. 어색한 곳을 찾으셨을까요?
- 바로 given 조건에서 Mockito.when 메서드를 이용해 Stubbing을 하는 곳이다
- BDD 시나리오에 맞게 given 조건에서 명칭이 같은 ( 가독성에 혼돈을 주지않는 ) 메서드를 사용하기 위해 BDDMockito가 등장했다
- 위에서 소개했던 Mockito의 사용 방법 예시를 보면 뭔가 어색한(?) 곳을 찾을 수 있다
- BDDMockito 적용
// dependency <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.21.0</version> </dependency>
BDDMockito도 Mockito와 마찬가지로 mockito-core 안에 있다
// JUnit5 + AssertJ + BDDMockito @ExtendWith(MockitoExtension.class) public class MemberServiceBddTest { @Mock MemberRepository memberRepository; @InjectMocks MemberService memberService; @DisplayName("멤버 전체 조회") @Test void getMembersTest() { // given BDDMockito.given(memberRepository.findAll()) .willReturn(List.of(Member.builder().name("test1").age(30).address("구로구").build(), Member.builder().name("test2").age(31).address("광진구").build())); // when List<MemberResponse> actual = memberService.getMembers(); // then assertThat(actual).isNotEmpty(); assertThat(actual).extracting("name","age","address") .contains(tuple("test1",30,"구로구"), tuple("test2",31,"광진구")); BDDMockito.then(memberRepository).should(BDDMockito.times(1)).findAll(); } }
- Mockito.when -> BDDMockito.given
- Mockito.verify -> BDDMockito.then
- BDDMockito는 Mockito 클래스를 상속하여 추가 Wrapping한 클래스라고 봐도 무방할 것 같다
( 즉 이름만 다를뿐 사용법은 같다 )
// BDDMockito class public class BDDMockito extends Mockito { .... }
참고 자료
728x90
반응형
'Tech > Test' 카테고리의 다른 글
Embedded MySQL를 이용해 테스트 환경 구축해보기 (0) | 2021.09.29 |
---|---|
JsonPath란? (0) | 2021.09.06 |
JUnit 5 공식 레퍼런스 (0) | 2021.08.25 |
Jacoco를 이용해 테스트 커버리지 관리해보자 (0) | 2021.08.08 |