-
🍸Mockito 이란?
테스트를 위한 Mock를 구축할 수 있게 해주는 자바 진영의 프레임워크
🧩Mockito Syntax
스프링 환경에서 코드를 작성했다. 스프링부트에서는 mock 객체를 라이브러리로 지원하기에 별다른 추가 빌드 코드 없이 사용 할 수 있다.
Cook class - mockito에서 사용할 클래스이다. 실제 객체를 생각하고 만들었다. 1. mock(className.class)
/** * mock(classToMock.class)로 mock 객체를 만들 수 있다. * 내부 구현은 동작하지 않고 0, null, false 등이 리턴된다. */ @Test void createMockTest() { // given Cook mockCook = mock(Cook.class); // when mockCook.setOrderedItem("hamburger"); // then assertThat(mockCook.getOrderedItem()).isEqualTo(null) ; }
mock 객체를 만드는 함수로, mock 함수를 사용해 mock을 만들 경우 내부 구현은 동작하지 않고, 내부 메소드를 호출시 0,null, false등이 호출된다.
2. Verify(mockClass, ... ).methodName()
/** * verify: mock 객체에 어떤 api가 호출되었는지, 몇 번 호출되었는지 확인 가능 */ @Test void verifyTest() { Cook mockCook = mock(Cook.class); mockCook.getOrderedItem(); // getOrderedItem이 한번이라도 호출되었는가? verify(mockCook).getOrderedItem(); mockCook.getOrderedItem(); mockCook.getOrderedItem(); // getOrderedItem 총 3번 호출됨 verify(mockCook, times(3)).getOrderedItem(); // getOrderedItem 적어도 2번 이상 호출됨 verify(mockCook, atLeast(2)).getOrderedItem(); }
'methodName' 메소드가 몇 번이나 호출 되었는지 알 수 있도록 해주는 메소드다. mockClass 옆에 인자로 주어진 함수로 몇 번이나 호출되었는지 확인 할 수도 있다. times(n)는 n번 호출되었는지 확인하는 함수고, atLeast(n)는 n번 이상 호출되었는지 확인 할 수 있는 함수다.
output 3. When(mockMethodCall).thenReturn(something)
/** * when: mock 객체가 어떤 값을 리턴하도록 만들 수 있음. 이것을 Stubbing이라고 한다. */ @Test void whenTest() { //given Cook mockCook = mock(Cook.class); // when when(mockCook.getOrderedItem()).thenReturn("hamburger"); // then assertThat(mockCook.getOrderedItem()).isEqualTo("hamburger"); }
When 함수를 사용해 특정한 값을 리턴하도록 적용 할 수 있다. 위의 코드에서 적용된 함수는 mockCook.getOrderedItem()이 호출되면 "hamburger"를 리턴하겠다는 뜻이다. 이를 stubbing이라고 한다.
output 4. ArgumentCaptor
/** * ArgumentCaptor: Mock 객체에 전달된 인자를 확인하는 용도로 사용 */ @Test void argumentCaptorTest() { Cook mockCook = mock(Cook.class); ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class); mockCook.setOrderedItem("pizza"); verify(mockCook).setOrderedItem(arg.capture()); assertThat(arg.getValue()).isEqualTo("pizza"); }
ArgumentCaptor를 사용해 mock 객체의 메소드에 어떤 인자들이 전달되었는지 확인 할 수 있다. 위의 코드를 보면 verify(mockCook).setOrderItem(arg.capture())라는 걸 볼 수 있는데, arg에 setOrderItem으로 전달되었던 데이터를 저장한다는 뜻이다.
output 5. Spy
/** * Spying: Mock 객체는 내부 구현이 동작하지 않는것에 비해 Spy객체는 실제 객체처럼 동작하고 * Verify로 어떤 메소드가 호출되었는지 확인 할 수있다. * 또한 When을 통해 일부 메소드를 stubbing 할 수 있다. */ @Test void spyingCook() { Cook spy = spy(Cook.class); spy.setOrderedItem("hamburger"); assertThat(spy.getOrderedItem()).isEqualTo("hamburger"); }
mock 객체와는 다르게 실제 객체처럼 동작하는 클래스이다. 실제로 cook에 정의되어있는 set 메소드등이 정상적으로 작동하여 테스트를 통과하는 모습을 볼 수 있다.
output ⚠️ 주의사항
@Test void spyingListError() { ArrayList spyList = spy(ArrayList.class); when(spyList.get(0)).thenReturn("apple"); when(spyList.get(1)).thenReturn("banana"); when(spyList.size()).thenReturn(10); assertThat(spyList.get(0)).isEqualTo("apple"); assertThat(spyList.get(1)).isEqualTo("banana"); assertThat(spyList.size()).isEqualTo(10); }
output IndexOutOfBoundException 발생
spy는 실제 코드처럼 동작하기에 when라인의 get()함수를 사용 할 경우 저장되어 있는 값이 없어 에러를 발생 시키는 것을 볼 수 있다. 이는 다음과 같이 doReturn(value).when(spyObject).method() 패턴을 사용하면 고칠 수 있다.
@Test void spyingListWhenFixed() { ArrayList spyList = spy(ArrayList.class); doReturn("apple").when(spyList).get(0); doReturn("banana").when(spyList).get(1); doReturn(10).when(spyList).size(); assertThat(spyList.get(0)).isEqualTo("apple"); assertThat(spyList.get(1)).isEqualTo("banana"); assertThat(spyList.size()).isEqualTo(10); }
6. Exception Throw
/** * 예외 발생 : when().thenThrow(ExceptionClass) 패턴 사용 */ @Test void whenGetUserInfoThrowException() { Cook mockCook = mock(Cook.class); when(mockCook.getOrderedItem()).thenThrow(NullPointerException.class); mockCook.getOrderedItem(); }
when의 thenThrow(ExceptionClass) 를 활용해 예외를 발생시킬 수 있다.
output NullPointerException이 발생한 것을 볼 수 있다.
발생한 예외를 테스트내에서 정상으로 표기하려면 다음과 같이 Junit5의 assertThrow를 사용하면 된다.
/** * 예외 발생 : when().thenThrow(ExceptionClass) 패턴 사용 * Junit5 사용시 assertThrow(Exception.class, () -> { dosomething() } 사용 */ @Test void whenGetUserInfoThrowException() { Cook mockCook = mock(Cook.class); when(mockCook.getOrderedItem()).thenThrow(NullPointerException.class); assertThrows(NullPointerException.class, () -> { mockCook.getOrderedItem(); }); }
output
References
https://www.baeldung.com/mockito-annotations
https://codechacha.com/ko/mockito-best-practice/
Java - Mockito를 이용하여 테스트 코드 작성하는 방법
Mockito는 Java에서 인기있는 Mocking framework입니다. Mockito로 객체를 mocking하여 Unit Test를 작성할 수 있습니다. 직접 Mock 객체를 만들 수 있지만 Mockito와 같은 Mocking framework을 사용하면 번거로운 코드를
codechacha.com