Mockito 사용해보기

반응형
반응형

*예제는 추후에 바꿔놓겠습니다. 지금은 만들기가 귀찮아서 공식문서꺼 사용하는것도 있네여ㅎㅎ;

mockito는 moking을 하기 위한 프레임워크입니다.

모킹은 
우리가 만든 객체를 사용하는 것이 아닌
프로그램이 임의적으로 만든 객체를 사용하는 것을 말합니다.
이는 진짜 객체와 가짜객체로 구분해서 불려지고 있습니다.

행동 정의

모킹 객체는 행동을 정의할 수 있다. 1번이 들어가면 "abc"가 나오고... 2번이 들어가면 "hello"가 나오는 식으로 진행된다.
Mockito에는 Stubbing이라는 용어가 존재한다.

인터넷에 찾아보니 나오지 않는다.. ㅜㅜ;

아무튼 [인프런] 최고 강사님들중 한 분인 [백기선]님의 말씀을 빌리자면
Stubbing : 행동을 정의하는 것이라고 한다.

결국 가짜객체를 진짜 객체처럼 사용?할 수 있게 도와 준다.

방법1)

@Test
  void list() {
    List mockedList = mock(List.class);
    when(mockedList.get(0)).thenReturn("hello");
}

방법2)

doReturn("hello").when(mockedList).get(anyInt());

mockito에서는 when이라는 키워드로 stubbing을 정의한다.
즉, 위 식을 해석하면 mockedList에 0번을 가져올때 "hello"을 리턴한다는 이야기다.
이것을 확인해보자.

정상적으로 나왔다.

현재는 0번을 넣었을 때만 "hello"를 리턴하게 해주었지만,
아무거나 넣었을때 "hello"를 리턴하게 하려면 어떻게 해야할까?

anyXXX()를 사용하면 된다.

 

@Test
void list() {
    List mockedList = mock(List.class);
    when(mockedList.get(anyInt())).thenReturn("hello");
    Assertions.assertEquals(mockedList.get(100),"hello");
}

 

근데 왜 any()는 안되지 ㅜㅜ;

exceptions 정의하기

    1. return이 존재할 경우

when(mockedList.get(anyInt())).thenThrow(new RuntimeException());

 

이제부터 뭘 넣든 에러입니다. 😉

  2. return이 존재하지 않는 경우(void일 경우)

doThrow(new RuntimeException()).when(mockedList).clear();

이제 부터 지우면 에러입니다.  😉
이 방식은 void가 아니여도 사용이 가능한 것 같습니다.

제대로 모킹되었는지 확인 작업

@Test
void list() {
     List mockedList = mock(List.class);
      mockedList.add("one");
      mockedList.clear();

     //확인   
      verify(mockedList).add("one");
      verify(mockedList).clear();
}

모킹된 객체를 확인할 때 사용되어진다.
예제는 리스트를 모킹해서 만들었다.
그곳에 "one"을 추가하고 리스트를 지운다.

그리고 verify키워드를 사용해서 순차적으로 동작하는지 확인한다.
즉, "one"이 추가 되었는지 리스트를 clear했는지 확인한다.

만약, 확인 작업이 실패했다면?"

"one"을 추가하는 것을 지웠다. 그랬더니

이런식으로 확인작업이 실패했다고 나온다.
참고로 verify는 확인 작업이기 때문에 지워도 아무런 문제가 되지 않는다. (다른걸 추가는 안된다.)

그렇다면 verify로는 어떤것을 할 수 있을까?

 1. times() : 몇 번 실행되었는지 확인

@Test
void list() {
    List mockedList = mock(List.class);
    mockedList.add("hello");  // 1번
    mockedList.add("do");  // 1번
    mockedList.add("do");  // 2번
    verify(mockedList,times(1)).add("hello");
}

자매품 : naver() : 실행하지 않을 경우

2. timeOut() : 시간내에 실행되었는지.

verify(mockedList,timeout(100)).add("hello");

100ms안에 되지 않으면 실패!

verify(mockedList,timeout(100).times(2)).add("hello");

이런것도 가능!

기타 : atMostOnce(),atLeastOnce(),atLeast()등 다양하게 존재!

순서 정하기

방법1)

@Test
void list() {
    List mockedList = mock(List.class);
    mockedList.add("hello");
    mockedList.add("go");
    InOrder inOrder = inOrder(mockedList);
    inOrder.verify(mockedList).add("hello");
    inOrder.verify(mockedList).add("go");
}

저장 순서대로 확인작업을 갖는다.

틀린다면?

틀린다.

방법2)

@Test
void list() {
     List firstMock = mock(List.class);
     List secondMock = mock(List.class);
     firstMock.add("hello");
     secondMock.add("go");

     InOrder inOrder = inOrder(firstMock, secondMock);

     inOrder.verify(firstMock).add("hello");
     inOrder.verify(secondMock).add("go");
}

모킹하는 대상이 다양할 경우 유용할 것 으로 예상!
1,2번 방법을 통합해서 사용도 가능!

어노테이이션 @Mock 사용

지금까지 mock()메소드로 모킹을 했다. 어노테이션으로도 사용하는 방법이 있다고 해서 소개한다.

@ExtendWith(MockitoExtension.class)
class HappyTest {

    @Mock
    List mockedList;

    @Test
    void list() {
        Assertions.assertNotNull(mockedList);
    }
}

이런식으로 추가하면 된다.

하나씩 살펴보자.

@ExtendsWith : Junit를 확장하는 방법중 하나로 선언적으로 등록하는 방법이다.

다른 방법도 되는지 살펴보자.

 

Junit5

*백기선의 더자바 애플리케이션을 테스트하는 다양한 방법을 바탕으로 작성 했습니다.! 더 자바, 애플리케이션을 테스트하는 다양한 방법 - 인프런 자바 프로그래밍 언어를 사용하고 있거나 공

b-programmer.tistory.com

@RegisterExtension 

@RegisterExtension
static MockitoExtension mockitoExtension = new MockitoExtension();

@Mock
List mockedList;

@Test
void list() {
    Assertions.assertNotNull(mockedList);
}

다행히 된다.

모킹해야되는 객체가 많은 경우에는 이 방법이 조금더 유용하다고 한다.

BDD스타일로 코드 작성하기

BBD는 Behavior Driven Development의 약자로 TDD에서 파생?된 개발방식이라고 한다.
즉, 테스트를 먼저 작성하구 기능을 만드는 식이다.

BDD는 크게

given
when
then

으로 구성되어 있다.

given : 뭐가 주어지는데?

given(mockedList.get(0)).willReturn("hello");

즉, 0번을 넣었을 때 hello가 리턴된다고 한다.

이것은 위에서 학습한 

when(mockedList.get(0)).thenReturn("hello");

과 같다.
하지만 지금은 BDD중이므로 이것은 사용하지 않는다.

when : 언제?

mockedList.add("hello");

mockList에 "hello"를 추가했을때!

then : 그래서 어떻게 되는데?

then(mockedList).should().add("hello");

이렇게 추가 된다!

이 방식은 위에서 학습한
verify와 같다.

verify(mockedList).add("hello");

예제가 조금 거지같긴 하지만 
아무튼 
내가 하고 싶은 말은

BDD는 예상/어디서/결과로 구성되는 느낌이다.

when이 BDD에 사용되지 않는다는 것이 아쉽다.ㅜㅜ;;(상관은 없지만)

SPY객체 사용하기

spy사용하게 되면, 진짜 객체의 값을 임의적으로 조작이 가능해진다.
마치 실제로 spy가 갈취하는 듯한....

@Test
void list() {
   List list = new LinkedList();
   List spy = spy(list);
     
    when(spy.size()).thenReturn(100);

   //using the spy calls *real* methods
    spy.add("one");
    spy.add("two");

        //prints "one" - the first element of a list
    System.out.println(spy.get(0));

        //size() method was stubbed - 100 is printed
    System.out.println(spy.size());

        //optionally, you can verify
    verify(spy).add("one");
    verify(spy).add("two");
}

현재 spy에는 값이 2개밖에 저장이 되지 않고 있다.
하지만 spy.size는 100를 리턴된다고 한다.

실제로도 그럴까?

놀랍게도 100이 출력된것을 확인 할 수 있다. 

값을 직접적으로 추가하는 것은 안되는 것 같다.

 

이 밖에도 @Spy, @InjectionMock등 다양한 것들이 존재한다. 
이들도 MockitoExtension.class를 추가해줘야한다.

반응형

'프로그래밍 언어 > 자바' 카테고리의 다른 글

나만의 DI프로그램 만들기  (0) 2021.01.03
리플렉션  (0) 2021.01.01
패키지  (0) 2020.12.30
Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test  (0) 2020.12.29
상속  (1) 2020.12.24

댓글

Designed by JB FACTORY