모의 객체 생성, 검증, 스텁을 지원하는 프레임워크이다. 스프링을 이용하지 않는 단위테스트를 진행할 때 사용하면 유용하다.
org.mockito:mockito-core를 추가 해주면 된다.
Mockito.mock()를 이용해서 생성을 원하는 객체의 클래스를 넣어주어 생성해주면 모의객체가 생성된다.
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock;
public class Sample {
@Test
void mockTest() {
GameNumGen genMock = mock(GameNumGen.class);
}
}
모의객체를 생성한 뒤 Mockito.when()을 이용해서 사용할 수 있지만 더 쉽게 읽힌다는 이유로 BDDMockito의 given()을 더 많이 사용한다고 한다.
given() 메서드부분을 보면 given()안에 모의객체의 어떤메서드가 어떠한 파라미터를 받아서 호출될 지를 작성하고 willReturn()부분에 리턴할 값을 작성한다.
import org.junit.jupiter.api.Test;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
public class Sample {
@Test
void mockTest() {
GameNumGen genMock = mock(GameNumGen.class);
given(genMock.generate(GameLevel.EASY)).willReturn("123");
String num = genMock.generate(GameLevel.EASY);
assertEquals("123", num);
}
}
given()에 설정한 메서드의 특정 인자 값외의 값을 넣으면 리턴타입의 기본값을 리턴한다.
예제에서는 GameLevel.EASY를 설정했지만 실제로 인자값으로는 GameLevel.NOMAL을 적용했기에 String의 기본 값인 null을 리턴한다.
import org.junit.jupiter.api.Test;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
public class Sample {
@Test
void mockTest() {
GameNumGen genMock = mock(GameNumGen.class);
given(genMock.generate(GameLevel.EASY)).willReturn("123");
String num = genMock.generate(GameLevel.NOMAL);
assertEquals(null, num);
}
}
여기서 특정 인자 값이 아닌 다수의 인자값을 설정하는 방법으로는 mockito.ArgumentMatchers를 이용하면 된다.
아래 메서드를 보면 any()를 이용했기에 모든 인자값에 대해서 "123"을 리턴하게 설정했다.
import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
public class Sample {
@Test
void mockTest() {
GameNumGen genMock = mock(GameNumGen.class);
given(genMock.generate(any())).willReturn("123");
String num = genMock.generate(GameLevel.EASY);
assertEquals("123", num);
String num2 = genMock.generate(GameLevel.NORMAL);
assertEquals("123", num2);
}
}
메서드 | 설명 |
---|---|
anyType | Type에 자료형의 타입을 넣어주면 파라미터가 해당 타입의 값이 일치 |
any() | 모든 타입에 대해 일치 |
matches(String), matches(Pattern) | 정규표현식을 이용한 String 값 일치 여부 |
eq(값) | 특정 값과 일치 여부 |
추가로 ArgumentMatchers를 파라미터중 하나라도 사용하면 모든 파라미터를 ArgumentMatchers로 표현해줘야한다
메서드(any(), "123") 이런식으로 사용 안되고 메서드(any(), eq("123"))으로 사용해야된다.
모의객체의 해당 메서드가 불렸는지 확인하는 방법으로 안불렸으면 테스트에 실패한다. BDDMockito.then이 사용된다.
then(모의객체).should().호출메서드(인자 값)으로 사용한다.
해당 메서드가 딱 한번만 호출되는지 확인하고 싶다면 should(only())처럼 Mockito.only()를 인자 값으로 넣어주면 된다.
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.*;
import static org.mockito.Mockito.mock;
public class MockTest {
@Test
void mockTest() {
GameNumGen genMock = mock(GameNumGen.class);
String num = genMock.generate(GameLevel.EASY);
then(genMock).should().generate(any());
}
}
모의 객체의 메서드가 호출될때 인자 값을 검증할 때가 있다. 이럴때는 mockito.ArgumentCaptor를 이용하여 확인할 수 있다.
@Test
@Test
void mockTest() {
GameNumGen genMock = mock(GameNumGen.class);
// generate()메서드 파라미터로 GameLevel.EASY을 사용
genMock.generate(GameLevel.EASY);
ArgumentCaptor<GameLevel> captor = ArgumentCaptor.forClass(GameLevel.class);
// captor.capture()를 이용해 해당 메서드의 파라미터를 캡쳐한다.
then(genMock).should().generate(captor.capture());
// captor.getValue()를 이용해 캡처된 파라미터 값을 가져와 검증하는 코드
assertThat(captor.getValue()).isEqualTo(GameLevel.EASY);
}
}
mock객체를 생성할때 어노테이션을 통해 생성하는 방법으로 mockito-jubit-jupiter를 의존해야한다(스프링부트에서는 자동으로 추가되어있음)
@ExtendWith(MockitoExtension.class)를 클래스 위에 붙여주고 모의객체를 생성할 값에 @Mock을 붙여주면 된다.
@ExtendWith(MockitoExtension.class)
public class MockTest {
@Mock
private GameNumGen genMock;
}