반응형

Mockito란?

  • 유닛 테스트를 위한 Java mocking framework
  • 자바 단위테스트에서 가짜 객체를 지원해주는 프레임워크
  • 즉, 단위 테스트를 하기 위해 Mock을 만들어주는 프레임워크
  • Mockito는 Szczepan Faber and friends에 의해 서비스가 제공
  • Mock 객체 생성, Mock 객체 동작을 지정, 그리고 테스트 대상 로직이 제대로 수행 되었는지 확인 가능
  • 자세한 내용은 공식 홈페이지 http://mockito.org/ 에서 확인 가능

 

 

Setup

Mockito는 JUnit위에서 동작하며 Mocking과 Verification을 도와주는 프레임워크이다.

build.gradle 파일을 아래의 코드와 같이 업데이트 하자.

 

build.gradle의 depencencies에

testImplementation group: 'org.mockito', name: 'mockito-all', version: '1.9.5'

라고 입력하거나 아래 링크를 타고 들어가 Mockito가 가능한 빌드 환경을 만들어주자.

 

 

https://mvnrepository.com/artifact/org.mockito/mockito-all/1.9.5

 

Maven Repository: org.mockito » mockito-all » 1.9.5

 

mvnrepository.com

 

Mock 생성하기

우선 아래와 같이 Animal이라는 객체를 하나 만든다.

 

package com.example.mockitotest;

import java.util.List;

public class Animal {
    private String name;
    private int age;
    private Boolean isFly;
    List<String> animalList;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public Boolean getFly() {
        return isFly;
    }
    public void setFly(Boolean fly) {
        isFly = fly;
    }

    public List getAnimalList(){
        return animalList;
    }
}

 

아래는 mock 객체를 생성하는 방법이다.

 

위의 Animal 클래스를 @Mock Annotation을 이용하여 선언 후

MockitoAnnotations.initMocks(this);를 통해 mock 객체를 생성해도 되고, 아래 주석처럼 바로 생성해도 된다.

package com.example.mockitotest;

import org.junit.Test;
import org.mockito.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

public class ExampleUnitTest {
    @Mock
    Animal animal;

    @Test
    public void mockTest(){
        MockitoAnnotations.initMocks(this);
        // 아래 코드로도 Mock 객체 생성 가능
        // Animal animal = mock(Animal.class);

        assertTrue(animal != null);
    }
}

 

 

when() 메서드 그리고 stub

When 메소드를 통해 하나의 메소드가 호출되었을 때 특정 값을 반환하라고 설정한다.

 

아래 mockTest를 보면 when과 stub가 명확해진다.

animal.getAge를 호출했다 가정했을 때, 30이라는 값을 return하라는 의미가 된다.

 

다시 생각해보면 아직 우리는 animal.age에 어떠한 나이도 설정하지 않았지만, animal.getAge()를 호출하면 30을 받을 수 있게 된다. 

 

이때 30, 참새, true가 stub에 해당한다.

 

아래 코드는 Error가 발생한다. 왜냐면 마지막 assertTrue(animal.getFly() == false)에서 true가 돼야하는데 false이기 때문

@Test
public void mockTest(){
    Animal animal = mock(Animal.class);
    assertTrue(animal != null);

    when(animal.getAge()).thenReturn(30);
    when(animal.getName()).thenReturn("참새");
    when(animal.getFly()).thenReturn(true);

    assertTrue(animal.getAge() == 30);
    assertTrue(animal.getName().equals("참새"));
    assertTrue(animal.getFly() == false);
}

 

아래 코드는 객체 자체를 stub로 만들어내는 과정이다.

animalList에 3개의 value를 넣고 when().thernReturn();을 이용하여 getAnimalList를 호출할 때, mock객체에 임의로 만든 ArrayList를 return해준다.

 

따라서 아래 System.out.println을 해보면 "코끼리"가 나타남을 알 수 있다.

@Test
public void mockTest() {
    Animal animal = mock(Animal.class);

    List<String> animalList = new ArrayList<>();
    animalList.add("호랑이");
    animalList.add("코끼리");
    animalList.add("독수리");

    when(animal.getAnimalList()).thenReturn(animalList);
    
    assertNotNull(animalList);
    assertEquals(animalList.size(), 3);
    
    System.out.println(animal.getAnimalList().get(1));
}

 

 

 

doThrow()를 통한 예외 발생

 

doThrow() 메서드를 이용하여 예외를 발생시킬 수 있다.

아래 코드와 같이 animal의 setAge를 20이라고 호출한다면, 예외를 발생시킬 것 이라고 하는 코드이고

아래에서 animal.setAge(20)을 통해 예외가 발생하는 과정이다. 

 

여기서 eq는 정확히라는 의미이고, eq(20)은 정확히 20이라는 의미를 가진다.

@Test
public void mockTest() {
    Animal animal = mock(Animal.class);
    doThrow(new RuntimeException()).when(animal).setAge(eq(20));
    animal.setAge(20);
}

 

아래 코드에서도 pass하다가 마지막 setAge(20)에서 결국 예외 처리가 발생한다.

@Test
public void mockTest() {
    Animal animal = mock(Animal.class);
    doThrow(new RuntimeException()).when(animal).setAge(eq(20));
    animal.setAge(203);
    animal.setAge(3);
    animal.setAge(23);
    animal.setAge(2);
    animal.setAge(333);
    animal.setAge(20);
}

 

 

 

Verify()를 이용한 검증

 

verifiy()는 해당 구문이 호출 되었는지를 체크한다.

단순한 호출뿐만 아니라 횟수나 타임아웃 시간까지 지정해서 체크해 볼 수 있다.

 

@Test
public void mockTest() {
    Animal animal = mock(Animal.class);
    animal.setName("참새");

    // n번 호출했는지 체크
    verify(animal, times(1)).setName(any(String.class)); // success
    // 호출 안했는지 체크
    verify(animal, never()).getName(); // success
    verify(animal, never()).setName(eq("호랑이")); // success
    verify(animal, never()).setName(eq("참새")); // fail
    // 최소한 1번 이상 호출했는지 체크
    verify(animal, atLeastOnce()).setName(any(String.class)); // success
    // 2번 이하 호출 했는지 체크
    verify(animal, atMost(2)).setName(any(String.class)); // success
    // 2번 이상 호출 했는지 체크
    verify(animal, atLeast(2)).setName(any(String.class)); // fail
    // 지정된 시간(millis)안으로 메소드를 호출 했는지 체크
    verify(animal, timeout(100)).setName(any(String.class)); // success
    // 지정된 시간(millis)안으로 1번 이상 메소드를 호출 했는지 체크
    verify(animal, timeout(100).atLeast(1)).setName(any(String.class)); // success
}

 

Mockito 메소드 종류

  • Mock() - 모의 객체를 생성하는 역할
  • when() - 협력객체 메소드 반환 값을 지정해주는 역할(stub)
  • verify() - SUT안의 협력객체 메소드가 호출 되었는지 확인
  • times() - 지정한 횟수 만큼 협력 객체 메소드가 호출 되었는지 확인
  • never() - 호출되지 않았는지 여부 검증
  • atLeastOnce() - 최소 한 번은 특정 메소드가 호출되었는지 확인
  • atLeast() - 최소 지정한 횟수 만큼 호출되었는지 확인
  • atMost() - 최대 지정한 횟수 만큼 호출되었는지 확인
  • clear() - 스텁을 초기화 한다
  • timeOut() - 지정된 시간 안에 호출되었는지 확인

 

 

 

참고 사이트

https://jdm.kr/blog/222

https://redskelt.github.io/junit/mockito/2017/06/22/junit04.html

https://bestalign.github.io/2016/07/08/intro-mockito-1/

https://github.com/mockito/mockito/wiki/Mockito-features-in-Korean

 

 

반응형