수색…


비고

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는 아직 베타 버전입니다.

버전

번역 메이븐 센트럴 릴리즈 노트 출시일
2.1.0 모키토 코어 변화들 2016-10-04
1.10.19 모키토 코어 변화들 2014-12-31

간단한 단위 테스트를 사용하여 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는 다음 순서로 의존성 주입을 해결하려고 시도합니다.

  1. 생성자 기반 주입 - 모의 ( constructor-based injection - mock)는 대부분의 인수를 사용하여 생성자에 주입됩니다 (일부 인수를 찾을 수없는 경우에는 null이 전달됩니다). 객체가 생성자를 통해 성공적으로 생성 된 경우 다른 전략은 적용되지 않습니다.
  2. 세터 기반 주입 - 모의는 유형별로 주입됩니다. 같은 유형의 속성이 여러 개 있으면 속성 이름과 모의 이름이 일치합니다.
  3. 직접 필드 주입 - 세터 기반 주입과 동일합니다.

앞서 언급 한 전략 중 하나라도 실패 할 경우 실패가보고되지 않습니다.

최신 버전의 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 메쏘드가 스터브 될 수 없다는 것에주의하십시오.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow