mockito 튜토리얼
mockito 시작하기
수색…
비고
Mockito는 간단한 API를 사용하여 읽기 쉬운 단위 테스트를 작성하는 기능을 제공하는 것을 목표로하는 Java Mocking 프레임 워크입니다. 대부분의 다른 프레임 워크가 사용하는 expect-run-verify 패턴을 남겨두면 다른 조롱 프레임 워크와 다릅니다.
대신에 클래스와 인터페이스를 조롱하는 방법 중 하나만을 알고 있으며 유연한 인수 매처를 기반으로 검증하고 스텁 할 수 있습니다.
현재 버전 1.10.19는 maven을 사용하는 것이 가장 좋습니다.
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
</dependency>
또는 gradle
repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:1.+" }
버전 2는 아직 베타 버전입니다.
버전
간단한 단위 테스트를 사용하여 Mockito
테스트 할 클래스는 다음과 같습니다.
public class Service {
private Collaborator collaborator;
public Service(Collaborator collaborator) {
this.collaborator = collaborator;
}
public String performService(String input) {
return collaborator.transformString(input);
}
}
공동 작업자는 다음과 같습니다.
public class Collaborator {
public String transformString(String input) {
return doStuff();
}
private String doStuff() {
// This method may be full of bugs
. . .
return someString;
}
}
우리의 테스트에서 우리는 Collaborator
와 그 버그의 의존성을 깨고 싶습니다. 그래서 우리는 Collaborator
를 조롱 할 것입니다 :
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.junit.Test;
public class ServiceTest {
@Test
public void testPerformService() throws Exception {
// Configure mock
Collaborator collaboratorMock = mock(Collaborator.class);
doReturn("output").when(collaboratorMock).transformString("input");
// Perform the test
Service service = new Service(collaboratorMock);
String actual = service.performService("input");
// Junit asserts
String expected = "output";
assertEquals(expected, actual);
}
}
Mockito 주석 사용하기
테스트 할 클래스는 다음과 같습니다.
public class Service{
private Collaborator collaborator;
public Service(Collaborator collaborator){
this.collaborator = collaborator;
}
public String performService(String input){
return collaborator.transformString(input);
}
}
공동 작업자는 다음과 같습니다.
public class Collaborator {
public String transformString(String input){
return doStuff();
}
private String doStuff()
{
// This method may be full of bugs
. . .
return someString;
}
}
우리의 테스트에서 우리는 Collaborator
와 그 버그의 의존성을 깨고 싶습니다. 그래서 우리는 Collaborator
를 조롱 할 것입니다. @Mock
주석을 사용하면 각 테스트에 대한 모의 인스턴스를 쉽게 만들 수 있습니다.
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.InjectMocks;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ServiceTest {
@Mock
private Collaborator collaboratorMock;
@InjectMocks
private Service service;
@Test
public void testPerformService() throws Exception {
// Configure mock
doReturn("output").when(collaboratorMock).transformString("input");
// Perform the test
String actual = service.performService("input");
// Junit asserts
String expected = "output";
assertEquals(expected, actual);
}
@Test(expected=Exception.class)
public void testPerformServiceShouldFail() throws Exception {
// Configure mock
doThrow(new Exception()).when(collaboratorMock).transformString("input");
// Perform the test
service.performService("input");
}
}
Mockito는 다음 순서로 의존성 주입을 해결하려고 시도합니다.
- 생성자 기반 주입 - 모의 ( constructor-based injection - mock)는 대부분의 인수를 사용하여 생성자에 주입됩니다 (일부 인수를 찾을 수없는 경우에는 null이 전달됩니다). 객체가 생성자를 통해 성공적으로 생성 된 경우 다른 전략은 적용되지 않습니다.
- 세터 기반 주입 - 모의는 유형별로 주입됩니다. 같은 유형의 속성이 여러 개 있으면 속성 이름과 모의 이름이 일치합니다.
- 직접 필드 주입 - 세터 기반 주입과 동일합니다.
앞서 언급 한 전략 중 하나라도 실패 할 경우 실패가보고되지 않습니다.
최신 버전의 Mockito에서이 메커니즘에 대한 자세한 정보는 최신 @InjectMocks
를 참조하십시오.
설치 및 설정
설치
Mockito를 설치하는 가장 좋은 방법은 빌드 시스템을 선택하여 mockito-core
에 의존성을 선언하는 것입니다. 2016 년 7 월 22 일부터 최신 비 베타 버전은 1.10.19이지만 2.x는 이미 마이그레이션하도록 권장됩니다 .
메이븐
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
요람
repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:1.+" }
Mockito 자체 외에 Hamcrest와 Objenesis가 포함 된 mockito-all
도 있습니다. Maven을 통해 주로 ant 사용자에게 제공되지만 Mockito 2.x에서는 배포가 중단되었습니다.
수입
Mockito 시설의 대부분의 정적 메서드입니다 org.mockito.Mockito
. 따라서 Mockito는 다음과 같이 정적으로 클래스에 가져올 수 있습니다.
import static org.mockito.Mockito.*;
문서 엔트리 포인트는이 클래스의 javadoc 에 있습니다.
객체에 대한 몇 가지 메소드 모방
mockito의 spy()
를 사용하여 객체의 일부 메소드를 조롱 할 수 있습니다.
예를 들어, 메소드 클래스가 작동하려면 웹 서비스가 필요하다고 상상해보십시오.
public class UserManager {
List<User> users;
public UserManager() {
user = new LinkedLisk<User>();
}
public void addUser(User user) {
if (isValid(user)) {
user.add(user);
} else {
throw new NotValidUserException();
}
}
protected boolean isValid(User user) {
//some online web service to check if user is valid
}
public int numberOfUsers() {
return users.size();
}
}
addUser
메소드는 UserManager
대한 유용한 Test를 만들기 위해 테스트되어야합니다. 그러나 여기에는 종속성이 있으며 isValid
에는 코드에 포함되지 않은 외부 웹 서비스가 필요합니다. 그런 다음이 외부 종속성을 무력화해야합니다.
이 경우, isValid
만을 모의하면 나머지 UserManager
메소드를 테스트 할 수 있습니다.
@Test
public void testAddUser() {
User user = mock(User.class);
UserManager manager = spy(new UserManager());
//it forces to manager.isValid to return true
doReturn(true).when(manager).isValid(anyObject());
manager.addUser(user);
assertTrue(manager.numberOfUsers(), 1);
}
user
가 유효하지 않은 시나리오를 쉽게 확인할 수 있습니다.
@Test(expectedExceptions = NotValidUserException.class)
public void testNotValidAddUser() {
User user = mock(User.class);
UserManager manager = spy(new UserManager());
//it forces to manager.isValid to return false
doReturn(false).when(manager).isValid(anyObject());
manager.addUser(user);
}
간단한 모 키토 테스트
이 예제는 조롱 된 ArrayList
사용하여 최소한의 Mockito 테스트를 보여줍니다.
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest
{
@Mock
ArrayList<String> listMock;
@Test
public void testAppend() {
// configure the mock to return "foobar" whenever "get()"
// is called on "listMock" with an int value as parameter
doReturn("foobar").when(listMock).get(anyInt());
String result = listMock.get(0);
assertEquals("foobar", result);
}
}
ArgumentCaptor로 인수 확인하기
모의 메서드에서 호출 된 메서드에 대한 인수를 확인하려면 ArgumentCaptor
클래스를 사용합니다. 이렇게하면 테스트 메소드에 인수를 추출하고 테스트 메소드에 대한 어설 션을 수행 할 수 있습니다.
이 예제는 주어진 ID로 사용자의 이름을 업데이트하는 메소드를 테스트합니다. 이 메소드는 사용자를로드하고 name
속성을 주어진 값으로 갱신 한 후 나중에 저장합니다. 테스트는 save
메소드에 전달 된 인수가 올바른 ID와 이름을 가진 User
객체인지 확인하려고합니다.
// This is mocked in the test
interface UserDao {
void save(User user);
}
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
@Mock
UserDao userDao;
@Test
public void testSetNameForUser() {
UserService serviceUnderTest = new UserService(userDao);
serviceUnderTest.setNameForUser(1L, "John");
ArgumentCaptor<User> userArgumentCaptor = ArgumentCaptor.forClass(User.class);
verify(userDao).save(userArgumentCaptor.capture());
User savedUser = userArgumentCaptor.getValue();
assertTrue(savedUser.getId() == 1);
assertTrue(savedUser.getName().equals("John"));
}
}
ArgumentMatcher를 사용하여 인수 확인
Mockito는 ArgumentMatcher<T>
를 확인하기 위해 추상 ArgumentMatcher<T>
클래스와 함께 Matcher<T>
인터페이스를 제공합니다. 그것은 ArgumentCaptor
와 같은 유즈 케이스에 대해 다른 접근법을 사용합니다. 또한 ArgumentMatcher는 조롱에도 사용할 수 있습니다. 두 유즈 케이스 모두 합리적으로 읽을 수있는 테스트 코드를 제공하는 Mockito.argThat()
메서드를 사용합니다.
verify(someMock).someMethod(Mockito.argThat(new ArgumentMatcher<String>() {
@Override
public boolean matches(Object o) {
return o instanceof String && !((String)o).isEmpty();
}
});
ArgumentMatcher의 JavaDocs에서 :
경고 : 테스트를 쉽게 읽을 수 없으므로 복잡한 인수 매칭, 특히 사용자 정의 인수 매처를 사용하는 것이 합리적입니다. 때로는 mocks에 전달 된 인수에 equals ()를 구현하는 것이 더 좋습니다 (Mockito는 자연스럽게 인수 일치에 equals ()를 사용합니다). 이렇게하면 테스트를보다 깨끗하게 할 수 있습니다.
Mockito가 조롱 한 객체 만들기
Mockito가 조롱 한 객체를 만드는 방법에는 두 가지가 있습니다.
- 주석을 통해
- 모의 함수를 통해
주석을 통해 :
JUnit 테스트 러너 :
@RunWith(MockitoJUnitRunner.class)
public class FooTest {
@Mock
private Bar barMock;
// ...
}
또한 Mockito의 JUnit을 사용할 수 있습니다 @Rule
는 AS와 동일한 기능 제공, MockitoJUnitRunner
하지만, 필요하지 않습니다 @RunWith
테스트 러너 :
public class FooTest {
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
@Mock
private Bar barMock;
// ...
}
@RunWith
나 @Rule
어노테이션을 사용할 수 @Rule
"손으로" @Rule
할 수도 있습니다 :
public class FooTest {
@Mock
private Bar barMock;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
// ...
}
모의 기능을 통해 :
public class FooTest {
private Bar barMock = Mockito.mock(Bar.class);
// ...
}
타입 삭제 때문에 위와 같이 일반 클래스를 조롱 할 수 없습니다. 기본 클래스를 조롱하고 명시 적으로 올바른 제네릭 형식으로 캐스팅해야합니다.
public class FooTest {
private Bar<String> genericBarMock = (Bar<String>) Mockito.mock(Bar.class);
// ...
}
조롱 된 객체에 비헤이비어 추가
Mockito.when(mock.returnSomething()).thenReturn("my val");
mock.returnSomething(); // returns "my val"
mock.returnSomething(); // returns "my val" again
mock.returnSomething(); // returns "my val" again and again and again...
두 번째 호출에서 다른 값을 원할 경우 원하는 return 인수를 thenReturn 메소드에 추가 할 수 있습니다.
Mockito.when(mock.returnSomething()).thenReturn("my val", "other val");
mock.returnSomething(); // returns "my val"
mock.returnSomething(); // returns "other val"
mock.returnSomething(); // returns "other val" again
모의 동작을 추가하지 않고 메서드를 호출하면 null이 반환됩니다.
barMock.mock.returnSomethingElse(); // returns null
조롱 된 메서드에 매개 변수가있는 경우 값도 선언해야합니다.
Mockito.when(mock.returnSomething("param 1")).thenReturn("my val 1");
Mockito.when(mock.returnSomething("param 2")).thenReturn("my val 2");
mock.returnSomething("param 1"); // returns "my val 1"
mock.returnSomething("param 2"); // returns "my val 2"
mock.returnSomething("param 3"); // returns null
param 값에 대해 신경 쓰지 않는다면 Matchers.any ()를 사용할 수 있습니다 :
Mockito.when(mock.returnSomething(Matchers.any())).thenReturn("p1");
mock.returnSomething("param 1"); // returns "p1"
mock.returnSomething("param other"); // returns "p1"
예외를 throw하려면 다음과 같이 메소드를 사용하십시오.
Mockito.when(mock.returnSomething()).thenThrow(new Exception());
mock.returnSomething(); // throws Exception
모의 객체에 전달 된 인자 검사
이 클래스가 있다고 가정하고 doSmth
메서드를 테스트하고 doSmth
. 이 경우 우리는 매개 변수 "val"이 foo
전달되는지보고 싶습니다. 객체 foo
가 조롱을받습니다.
public class Bar {
private final Foo foo;
public Bar(final Foo foo) {
this.foo = foo;
}
public void doSmth() {
foo.bla("val");
}
}
ArgumentCaptor
하여이 작업을 수행 할 수 있습니다.
@Mock
private Foo fooMock;
@InjectMocks
private Bar underTest;
@Captor
private ArgumentCaptor<String> stringCaptor;
@Test
public void should_test_smth() {
underTest.doSmth();
Mockito.verify(fooMock).bla(stringCaptor.capture());
assertThat(stringCaptor.getValue(), is("val"));
}
조롱 된 객체에 대한 메소드 호출 확인
조롱 된 객체에서 메소드가 호출되었는지 확인하려면 Mockito.verify
메소드를 사용할 수 있습니다.
Mockito.verify(someMock).bla();
이 예제에서 우리는 someMock
모의 객체에서 bla
라는 메서드가 호출되었다고 주장한다.
특정 매개 변수로 메소드가 호출되었는지 확인할 수도 있습니다.
Mockito.verify(someMock).bla("param 1");
메서드가 호출 되지 않았는지 VerificationMode
하려면 추가 VerificationMode
매개 변수를 전달하여 다음을 verify
.
Mockito.verify(someMock, Mockito.times(0)).bla();
이 메소드가 두 번 이상 호출되었는지 확인하고자하는 경우에도 작동합니다 (이 경우 bla
메소드가 23 회 호출되었음을 확인합니다).
Mockito.verify(someMock, Mockito.times(23)).bla();
다음은 VerificationMode
매개 변수의 예입니다. 메서드를 호출해야하는 횟수를 더 많이 제어 할 수 있습니다.
Mockito.verify(someMock, Mockito.never()).bla(); // same as Mockito.times(0)
Mockito.verify(someMock, Mockito.atLeast(3)).bla(); // min 3 calls
Mockito.verify(someMock, Mockito.atLeastOnce()).bla(); // same as Mockito.atLeast(1)
Mockito.verify(someMock, Mockito.atMost(3)).bla(); // max 3 calls
스터 빙 void 메소드
void
메소드는 doThrow () , doAnswer () , doNothing () , doCallRealMethod () 패밀리 메소드 패밀리를 사용하여 스텁 될 수 있습니다.
Runnable mock = mock(Runnable.class);
doThrow(new UnsupportedOperationException()).when(mock).run();
mock.run(); // throws the UnsupportedOperationException
컴파일러가 void
메쏘드를 인자로 사용하지 않을 when(..)
사용하여 void
메쏘드가 스터브 될 수 없다는 것에주의하십시오.