Mokito
Mock : 진짜 객체와 비슷하게 동작하지만 프로그래머가 직접 그 객체의 행동을 관리하는 객체
Mockito : Mock 객체를 쉽게 만들고 관리하는 검증할 수 있는 방법을 제공한다.
테스트를 작성하는 자바개발자 50% 이상 사용하는 Mock 프레임워크
https://site.mockito.org/
단위 테스트에 대한 고찰
https://martinfowler.com/bliki/UnitTest.html
테스트의 단위는 행동? 모든 의존성을 끊고 단위테스트를 한다 보다는 행동단위로 테스트한다.
Mockito 레퍼런스
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
Mokito 시작하기
스프링 부트 2.2+ 프로젝트 생성시 spring-boot-starter-test에서 자동으로 Mockito 추가해 줌. 스프링 부트 쓰지 않는다면, 의존성 직접 추가.
<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() 메소드로 만드는 방법
구현체가 없는 경우 mock객체를 만든다.
MemberService memberService = mock(MemberService.class);
StudyRepository studyRepository = mock(StudyRepository.class);
@Mock 애노테이션으로 만드는 방법
- JUnit 5 extension으로 MockitoExtension을 사용해야 한다.
- 필드
- 메소드 매개변수
@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);
}
}
Mock 객체 Stubbing(행동조작)
모든 Mock 객체의 행동
- Null을 리턴(Optional 타입은 Optional.empty return)
- Primitive 타입은 기본 Primitive값
- 콜렉션은 비어있는 콜렉션
- Void 메서드는 예외를 던지지 않고 아무런 일도 발생하지 않는다.
Mock 객체를 조작
- 특정한 매개변수를 받은 경우 특정한 값을 리턴하거나 예외를 던지도록 할 수 있다
- void 메소드 특정 매개변수를 받거나 호출된 경우 예외를 발생 시킬 수 있다.
- 메소드가 동일한 매개변수로 여러번 호출될 때 각기 다르게 행동하도록 조작할 수 있다.
Member member = new Member();
member.setId(1L);
member.setEmail("orange2652@gmail.com");
when(memberService.findById(1L)).thenReturn(Optional.of(member));
//when(memberService.findById(any()).thenReturn(Optional.of(member)); 어떠한값이 들어오더라도 thenReturn값 리턴
Mock객체 확인
Mock객체가 어떻게 사용됐는지 확인할 수 있다.
-
특정 메소드가 특정 매개변수로 몇번 호출되었는지, 최소 한번은 호출 됐는지, 전혀 호출되지 않았는지
-
Verifying exact number of invocations
studyService.createStudy(1L, study); assertEquals(member, study.getOwner()); verify(memberService, times(1)).notify(any()); //notify라는 메서드가 한번 호출되어야 한다. verify(memberService, never()).validate(any()); //호출되지 말아야 한다.
-
-
어떤 순서대로 호출했는지
-
//inOrder.verify 에서 정해놓은 순서대로 호출되어야 한다. InOrder inOrder = inOrder(memberService); inOrder.verify(memberService).notify(study); inOrder.verify(memberService).notify(member);
-
-
특정 시간 이내에 호출됐는지
-
verify(mock, timeout(100)/times(1)).someMethod();
-
-
특정 시점 이후에 아무 일도 벌어지지 않았는지
-
verifyNoMoreInterations(memberService); //다른일을 하지않아야한다.
-
Mockito BDD(Behavior_Driven_Development) 스타일 API
BDD : 애플리케이션이 어떻게 “행동” 해야 하는지에 대한 공통된 이해를 구성하는 방법으로, TDD에서 착안.
행동에 대한 스팩
- Title
- Narrative
- As a / I want / so that
- Acceptance criteria
- Given / When / Then
When -> Given
given(memberService.findById(1L)).willReturn(Optional.of(member));
given(studyRepository.save(study)).willReturn(study);
Verify -> Then
then(memberService).should(times(1)).notify(study);
then(memberService).should(shouldHaveNoMoreInterations();
참고
https://javadoc.io/static/org.mockito/mockito-core/3.2.0/org/mockito/BDDMockito.html https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#BDD_behavior_verification 더 자바, 애플리케이션을 테스트하는 다양한 방법