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
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://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
'Applied > Unit Test' 카테고리의 다른 글
[JUnit] Espresso를 위한 JUnit 기초 (0) | 2020.02.03 |
---|---|
[Espresso] Espresso 개념 및 환경 구성 (0) | 2020.01.30 |
[Espresso] Espresso를 이용한 UI Test 예제 (0) | 2020.01.29 |
[Mockito] Mock 개념(Mock Object) (0) | 2019.07.16 |
[JUnit] Android UnitTest, JUnit을 이용한 유닛 테스트 (0) | 2019.07.09 |