프로그래밍 노트/TEST를 해보자

모키토 프레임워크(Mockito framework)

깡냉쓰 2019. 11. 13. 22:44
728x90
반응형

Junit 프레임워크에서 많이사용되는 모키토 프레임워크에 대해 알아보자.

차별점

  1. 테스트 그 자체에 집중한다.
  2. 테스트 스텁을 만드는 것과 검증을 분리시켰다.
  3. Mock 만드는 방법을 단일화했다.
  4. 테스트 스텁을 만들기 쉽다.
  5. API가 간단하다.
  6. 프레임워크가 지원해주지 않으면 안되는 코드를 최대한 배제했다.
  7. 실패 시에 발생하는 에러추적이 깔끔하다.

환경구성

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>

기본 사용법

Mockito는 Stub 작성과 Verify가 중심을 이루며 다음과 같은 순서로 진행된다.

  1. CreateMock : 인터페이스에 해당하는 Mock 객체를 만든다.
  2. Stub : 테스트에 필요한 Mock 객체의 동작을 지정한다.(필요시만)
  3. Exercise : 테스트 메소드 내에서 Mock객체를 사용한다.
  4. Verify : 메소드가 예상대로 호출됐는지 검증한다.

1. Mock 객체 만들기

1-1. Mockito.mock(타깃 인터페이스)

@Test
public void test(){
    // static 메소드 mock을 이용해 인터페이스나 클래스를 지정한다. 
    // 리턴 타입의 기본값으로 동작한다. int는 0, boolean은 false, 클래스 타입은 null
    List mockedList = mock(List.class);
    System.out.println(mockedList.size());
}

아래와 같이 Post 클래스를 만들었다고 가정하자.

public class Post{
    private String writer;
    private String content;
}

mock()메소드를 통해 손쉽게 목객체를 만들 수 있다.

@Test
public void test(){
    Post post = mock(Post.class);
    assertThat(post, is(notNullValue())); // Hamcrest 사용
    assertTrue(p!=null);
}

1-2. @Mock 어노테이션 사용

@Mock
Post post;

@Test
public void test(){
    // Mockito 어노테이션이 선언된 변수들에 한해서 목객체를 만든다.
    // 보통 Junit @Before부분에 넣는다.
    MockitoAnnotations.initMocks(this); 
    assertThat(post, is(notNullValue()));
}

2. 예상값 지정

스텁 → 수행 → 검증으로 단순화되어 있음.

3. 테스트에 사용할 스텁 만들기

when(Mock_객체의_메소드).thenReturn(리턴값);
when(Mock_객체의_메소드).thenThrow(예외);
스텁은 필요할 때만 만드는 것이 원칙이다.
메소드 호출 여부를 검증만 할 때는 사용하지 않는다.

@Test
public void test(){
    List mockedList = mock(List.class);

    // Mock 객체를 사용한다.
    mockedList.add("item");
    mockedList.clear();

    // 검증
    verify(mockedList).add("item");
    verify(mockedList).clear();

    // Stub 만들기
    when(mockedList.get(0)).thenReturn("item");
    when(mockedList.size()).thenReturn(1);
    when(mockedList.get(1)).thenThrow(new RuntimeException());

    System.out.println(mockedList.get(0)); // item
    System.out.println(mockedList.size()); // 1
    System.out.println(mockedList.get(2)); 
    System.out.println(mockedList.get(1)); // RuntimeException 발생
}

4. 검증

verify(Mock_객체).Mock_객체의_메소드;
verify(Mock_객체, 호출횟수지정_메소드).Mock_객체의_메소드;
Mock 객체의 특정 메소드가 호출됐는지 확인한다.

@Test
public void testMockList(){
    List mockedList = mock(List.class);
    verify(mockedList).size(); // verify를 통해 mockedList.size()가 호출됐는지 확인(상태 기반 테스트에 유용)
}
// size()메소드를 호출했는지 검증했지만, 호출을 하지 않았음
Wanted but not invoked:
list.size();
-> at com.corn.mokito.MockTest.testMockList(MockTest.java:37)
Actually, there were zero interactions with this mock.

궁금의 TDD 템플릿

BDD(Behavior Driven Development)스타일의 궁극의 스타일은 아래와 같다.

@Test
public void shouldDoSomethingCool() throws Exception{
        // given : 선행조건 기술

        // when : 기능 수행

        // then : 결과 확인

}
728x90
반응형