Mock 객체 Stubbing
stub이란 토막,꽁초,남은부분,몽당연필.. 이라는 뜻으로 dummy객체가 마치 실제로 동작하는 것 처럼 보이도록 만들어놓은 것
- 즉 Mock 객체의 행동을 조작하는 것
모든 Mock 객체의 행동
- Null을 리턴한다. (Optional 타입은 Optional.empty 리턴. 즉 비어있는 옵셔널 객체)
- Primitive 타입은 기본 Primitive 값.
- 콜렉션은 비어있는 콜렉션.
- Void 메소드는 예외를 던지지 않고 아무런 일도 발생하지 않는다.
- 예제1
- memberService.findById(1L) member 객체를 나오게 할라면 다음과 같이 쓰면 된다.
- 만약 2L, 3L 등 다른 member 객체를 나오게 한다면 오류가 난다.
- 1L로만 member를 나오게 했기 때문
- 즉 when().thenReturn은 mock 객체를 직접 핸들링한다
- org.mockito.ArgumentMatchers.
any()
; 메서드를 사용하면
항상 같은 객체가 나온다 (아무 값이나 상관 없다).
- 만약 2L, 3L 등 다른 member 객체를 나오게 한다면 오류가 난다.
@Test void createNewStudy(@Mock MemberService memberService, @Mock StudyRepository studyRepository) { Member member = new Member(); member.setId(1L); member.setEmail("youngsoo@naver.com"); Optional<Member> byId = memberService.findById(1L); when(memberService.findById(1L)) .thenReturn(Optional.of(member)); Study study = new Study(10, "java"); Optional<Member> findById = memberService.findById(1L); assertEquals("youngsoo@naver.com", findById.get().getEmail()); }
- 예외를 던지는 doThrow() org.mockito.Mockito.doThrow;
-
doThrow(new IllegalArgumentException()) .when(memberService).validate(); assertThrows(IllegalArgumentException.class, () -> { memberService.validate(); });
-
- 순서대로 호출하기
-
when(memberService.findById(any())) .thenReturn(Optional.of(member)) .thenThrow(new RuntimeException()) .thenReturn(Optional.empty());
- 첫번째 호출 멤버
- 두번째 호출 런타임 익셉션
- 세번째 호출 빈 옵셔널 객체를 내보낸다
Mockito에서는 아래의 stub메서드들을 지원.doReturn()
: Mock 객체가 특정한 값을 반환해야 하는 경우 사용
doReturn(3).when(p).add(anyInt(), anyInt());
doNothing()
: Mock 객체가 아무 것도 반환하지 않는 경우 사용(void)
@Test
public void example(){
Person p = mock(Person.class);
doNothing().when(p).setAge(anyInt());
p.setAge(20);
verify(p).setAge(anyInt());
}
doThrow()
: Mock 객체가 예외를 발생시키는 경우 사용
@Test(expected = IllegalArgumentException.class)
public void example(){
Person p = mock(Person.class);
doThrow(new IllegalArgumentException()).when(p).setName(eq("JDM"));
String name = "JDM";
p.setName(name);
}
Stub의 doReturn, thenReturn의 차이
Mockito를 사용하다보면 코드들에 doThrow
, doReturn
등의 형식이 아닌
thenReturn()
, thenThrow()
등의 형식도 볼 수 있을 것이다. 둘의 차이점은 다음과 같다.
doReturn
- 실제로 메서드를 호출하고 리턴값을 임의로 정의할 수 있다.
- 메서드를 실제로 수행하여 메서드 작업이 오래걸릴 경우 끝날 때 까지 기다려야한다.
- 실제 메서드를 호출하기 때문에 대상 메서드에 문제점이 있을 경우 발견할 수 있다.
doReturn(6).when(cal).add(2, 4);
thenReturn
- 메서드를 실제로 호출하지 않으며 리턴값을 임의로 정의할 수 있다.
- 실제 메서드를 호출하지 않기 때문에 대상 메서드에 문제점이 있어도 알 수 없다.
when(cal.add(2, 4)).thenReturn(6);
Mock 객체 확인
Mock 객체가 어떻게 사용이 됐는지 확인할 수 있다.
- 특정 메소드가 특정 매개변수로 몇번 호출 되었는지,
- 최소 한번은 호출 됐는지,
- 전혀 호출되지 않았는지
- Verifying exact number of invocations
org.mockito.Mockito.verify()
메서드- 예제 : 멤버 서비스에서 딱 1번 notify란 메서드가 study라는 매개변수를 가지고 호출 되어야 한다
-
verify(memberService, times(1)).notify(study);
- any()도 가능하다.
- 어떤 순서대로 호출했는지
- Verification in order
org.mockito.Mockito.inOrder()
,inOrder.verify()
메서드- 예제 : 멤버 서비스에서 notify(study) 메소드가 notify(member) 보다 먼저 호출되어야 한다.
-
verify(memberService, times(1)).notify(study); verify(memberService, times(1)).notify(member); InOrder inOrder = inOrder(memberService) inOrder.verify(memberService).notify(study); inOrder.verify(memberService).notify(member);
- 이후에 더이상 아무 액션이 일어나면 안된다 할 때는
verifyNoMoreInteractions(Object mocks...)
메서드
- 특정 시간 이내에 호출됐는지
- Verification with timeout
- 특정 시점 이후에 아무 일도 벌어지지 않았는지
- Finding redundant invocations
참고
- 인프런 백기선님 강의 더 자바, 애플리케이션을 테스트하는 다양한 방법
- https://velog.io/@seongwon97/Unit-Test-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8
'테스트 > JUnit' 카테고리의 다른 글
RefectionTestUtils - private 필드 값 주입, private 테스트 (0) | 2022.12.13 |
---|---|
Spring Boot JPA Test @DataJpaTest 기본 설정 (3) | 2022.08.27 |
JUnit5 - Java에서의 단위테스트4 Mock, Mockito (0) | 2022.08.21 |
JUnit5 - Java에서의 단위테스트3 - 테스트 인스턴스들 (0) | 2022.08.21 |
JUnit5 - Java에서의 단위테스트2 - 테스트 반복 (0) | 2022.08.21 |