반응형
Mockito 시작
- Mockito 의존성 추가
mockito-core
: Mokito 기본 기능 제공
mockito-junit-jupiter
: JUnit 에서 Mokito를 연동해서 사용할수 있도록 한다(JUnit 확장 구현체)
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.1.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>3.1.0</version> <scope>test</scope> </dependency>
- Mock을 활용한 테스트를 작성하기 위해 알아야 할 세 가지 방법
- Mock을 만드는 방법
- Mock이 어떻게 동작해야 하는지 관리하는 방법
- Mock의 행동을 검증하는 방법
Mock 객체 만들기
Mockito.mock()
메소드로 만드는 방법MemberService memberService = mock(MemberService.class); StudyRepository studyRepository = mock(StudyRepository.class);
@Mock
애노테이션으로 만드는 방법- JUnit 5 extension으로 MockitoExtension을 사용해야 한다.(
@Mock
애노테이션을 처리하기 위해서)
- 애노테이션 사용위치
- 필드 및 메소드 매개변수
@ExtendWith(MockitoExtension.class) class StudyServiceTest { @Mock MemberService memberService; @Mock StudyRepository studyRepository; . . .
@ExtendWith(MockitoExtension.class) class StudyServiceTest { @Test void createStudyService(@Mock MemberService memberService, @Mock StudyRepository studyRepository) { StudyService studyService = new StudyService(memberService, studyRepository); assertNotNull(studyService); } }
- JUnit 5 extension으로 MockitoExtension을 사용해야 한다.(
Mock 객체 Stubbing(Mock 객체의 동작 관리)
- Stubbing
- 호출에 대해서 미리 준비된 답변을 제공한다.
- 모든 Mock 객체의 기본적인 행동
- Null을 리턴한다. (Optional 타입은 Optional.empty 리턴)
- Primitive 타입은 기본 Primitive 값을 리턴한다.
- boolean, Boolean : false
- int, Integer : 0
- ...
- 콜렉션은 비어있는 콜렉션으로 리턴한다.
- Void 메소드는 예외를 던지지 않고 아무런 일도 발생하지 않는다.
- Mock 객체를 조작해서 기본적인 행동을 변경할 수 있다.(Stubbing)
- 특정한 매개변수(예 : 1L)를 받은 경우 특정한 값을 리턴하거나 예외를 던지도록 만들 수 있다.
- thenRetun
- 예)
thenReturn(Optional.of(member));
- 예)
- thenThrow
- 예)
thenThrow(IllegalArgumentException.class);
- 예)
Member member = new Member(); member.setId(1L); member.setEmail("devhistory@email.com"); when(memberServiceMock2.findById(1L)).thenReturn(Optional.of(member)); //memberServiceMock2.findById(1L)이 호출되면, 예외를 던지도록 설정 //when(memberServiceMock2.findById(1L)).thenThrow(new RuntimeException()); Optional<Member> findById = memberServiceMock2.findById(1L); assertEquals("devhistory@email.com", findById.get().getEmail());
Argument matchers
를 이용하여 어떤 파라미터(예 : 1L, 2L, 3L, ...)를 받아도 특정한 값을 리턴하거나 예외를 던지도록 만들 수 있다.
Member member = new Member(); member.setId(1L); member.setEmail("devhistory@email.com"); when(memberServiceMock2.findById(any())).thenReturn(Optional.of(member)); //memberServiceMock2.findById(any())이 호출되면, 예외를 던지도록 설정 //when(memberServiceMock2.findById(any())).thenThrow(new RuntimeException()); Optional<Member> findById = memberServiceMock2.findById(3L); assertEquals("devhistory@email.com", findById.get().getEmail());
- thenRetun
- Void 메소드 특정 매개변수를 받거나 호출된 경우 예외를 발생 시킬 수 있다.
- doThrow
- 예)
doThrow(new IllegalArgumentException()).when(memberServiceMock2).validate(1L);
- 예)
//memberServiceMock2의 validate(1L)가 호출되면 예외를 던지도록 설정 doThrow(new IllegalArgumentException()).when(memberServiceMock2).validate(1L); assertThrows(IllegalArgumentException.class, () -> { memberServiceMock2.validate(1L); });
- doThrow
- 메소드(예 : findById)가 동일한 매개변수로 여러 번 호출될 때 각기 다르게 행동하도록 조작할 수 있다.
when(memberServiceMock2.findById(any())) .thenReturn(Optional.of(anyMember)) .thenThrow(new RuntimeException()) .thenReturn(Optional.empty()); Optional<Member> byId = memberServiceMock2.findById(1L); assertEquals("any@email.com", findById2.get().getEmail()); assertThrows(RuntimeException.class, () -> { memberServiceMock2.findById(2L); }); assertEquals(Optional.empty(), memberServiceMock2.findById(3L));
- 특정한 매개변수(예 : 1L)를 받은 경우 특정한 값을 리턴하거나 예외를 던지도록 만들 수 있다.
Mock 객체 확인
- Mock 객체가 어떻게 사용이 됐는지 확인할 수 있다.
- 특정 메소드가 특정 매개변수로 몇 번 호출 되었는지, 최소 한 번은 호출 됐는지, 전혀 호출되지 않았는지 등
- verify
- 예)
verify(memberService, times(1)).notify(study);
memberService의 notify(study)가 한 번만 호출되어야하는 경우
- 예)
Study study = new Study(10, "테스트"); studyService.createNewStudy(1L, study); //createNewStudy 메소드 내부에서 memberService의 notify(study) 수행횟수 확인 verify(memberService, times(1)).notify(study);
- verify
- 어떤 순서대로 호출했는지
- inOrder
Study study = new Study(10, "테스트"); studyService.createNewStudy(1L, study); //createNewStudy 메소드 내부에서 memberService의 notify 호출 순서일치여부 확인 InOrder inOrder = inOrder(memberService); inOrder.verify(memberService).notify(study); inOrder.verify(memberService).notify(member);
- 특정 시간 이내에 호출됐는지
- JUnit 5의 Timeout 메소드 사용 고려
- 특정 메소드가 특정 매개변수로 몇 번 호출 되었는지, 최소 한 번은 호출 됐는지, 전혀 호출되지 않았는지 등
- 특정 시점 이후에 아무 일도 벌어지지 않았는지
- 특정 시점 기준 : 이전에 verify로 확인한 시점을 의미한다.
- 예)
memberService.notify(study)
- 예)
- 특정 시점을 기준으로 다른 어떤 것도 호출되지 않았는지 확인한다.
- 예)
memberService.notify(study)
호출 이후에는memberService
에서 어떤 메소드도 호출되면 안된다. 호출 되었다면 테스트 통과 불가.
- 검증하려는 Mock 객체와 무관한 메소드는 영향을 받지 않는다.
- 예)
//verification verify(memberService, times(1)).notify(study); //특정 시점 이후(memberService.notify(study) 호출 이후)에는 memberService의 어떤 동작도 발생하면 안된다. verifyNoMoreInteractions(memberService);
- 특정 시점 기준 : 이전에 verify로 확인한 시점을 의미한다.
[참고자료]
더 자바, 애플리케이션을 테스트하는 다양한 방법, 백기선
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
반응형
'Java > Test Framework' 카테고리의 다른 글
[더 자바, 애플리케이션을 테스트하는 다양한 방법] Mockito - BDD 스타일 Mockito 테스트 (0) | 2021.08.01 |
---|---|
[더 자바, 애플리케이션을 테스트하는 다양한 방법] JUnit 5 - 확장 모델 (0) | 2021.07.27 |
[더 자바, 애플리케이션을 테스트하는 다양한 방법] JUnit 5 - 테스트 설정 파일 (0) | 2021.07.26 |
[더 자바, 애플리케이션을 테스트하는 다양한 방법] JUnit 5 - 테스트 인스턴스 전략 변경 및 테스트 순서 설정 (0) | 2021.07.26 |
[더 자바, 애플리케이션을 테스트하는 다양한 방법] JUnit 5 - 테스트 반복수행 (0) | 2021.07.25 |