수색…


단순 모의

Mockito는 (최종적이지 않은) 클래스와 인터페이스의 모의 객체를 생성 할 수있는 단일 크기의 메소드를 제공합니다.

Dependency mock = Mockito.mock(Dependency.class);

Dependency 이 인터페이스인지 클래스인지에 Dependency 없이 Dependency 의 모의 인스턴스가 생성됩니다.

그런 다음 Mockito.when (x) .thenReturn (y) 표기법을 사용하여 해당 모의 메서드 호출을 스텁하는 것이 가능합니다.

Mockito.when(mock.possiblyBuggyMethod()).thenReturn("someString");

따라서 Dependency.possiblyBuggyMethod() 호출은 단순히 "someString" 반환합니다.

타입 시큐리티가 아니기 때문에 대부분의 유스 케이스에서는 낙심하는 또 다른 표기법이 있습니다.

Mockito.doReturn("someString").when(mock).possiblyBuggyMethod()

모방 기본값으로

간단한 모의가 모든 호출에 null (또는 기본 프리미티브의 기본값)을 반환하는 동안 해당 동작을 변경할 수 있습니다.

Dependency mock = Mockito.mock(Dependency.class, new Answer() {

        @Override
        public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
            return "someString";
        }
    });

또는 lambdas 사용 :

Dependency mock = Mockito.mock(Dependency.class, (Answer) invocationOnMock -> "someString");

이 예제는 모든 호출에 "someString"을 반환하지만 answer-method에서 모든 로직을 정의 할 수 있습니다.

특수 효과를 사용하여 수업 조롱

테스트중인 클래스 :

public class GreetingsService { // class to be tested in isolation
    private UserService userService;

    public GreetingsService(UserService userService) {
        this.userService = userService;
    }

    public String getGreetings(int userId, LocalTime time) { // the method under test
        StringBuilder greetings = new StringBuilder();
        String timeOfDay = getTimeOfDay(time.getHour());
        greetings.append("Good ").append(timeOfDay).append(", ");
        greetings.append(userService.getFirstName(userId)) // this call will be mocked
                .append(" ")
                .append(userService.getLastName(userId)) // this call will be mocked
                .append("!");
        return greetings.toString();
    }

    private String getTimeOfDay(int hour) { // private method doesn't need to be unit tested
        if (hour >= 0 && hour < 12)
            return "Morning";
        else if (hour >= 12 && hour < 16)
            return "Afternoon";
        else if (hour >= 16 && hour < 21)
            return "Evening";
        else if (hour >= 21 && hour < 24)
            return "Night";
        else
            return null;
    }
}

이 인터페이스의 동작은 조롱받을 것입니다.

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

UserService 의 실제 구현을 가정합니다.

public class UserServiceImpl implements UserService {
    @Override
    public String getFirstName(int userId) {
        String firstName = "";
        // some logic to get user's first name goes here
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return firstName;
    }

    @Override
    public String getLastName(int userId) {
        String lastName = "";
        // some logic to get user's last name goes here
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return lastName;
    }
}

Mockito의 Junit 테스트 :

public class GreetingsServiceTest {
    @Mock
    private UserServiceImpl userService; // this class will be mocked
    @InjectMocks
    private GreetingsService greetingsService = new GreetingsService(userService);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGetGreetings_morning() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(99)).thenReturn("John");
        when(userService.getLastName(99)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(99, LocalTime.of(0, 45));
        Assert.assertEquals("Failed to get greetings!", "Good Morning, John Doe!", greetings);
    }

    @Test
    public void testGetGreetings_afternoon() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(11)).thenReturn("Jane");
        when(userService.getLastName(11)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(11, LocalTime.of(13, 15));
        Assert.assertEquals("Failed to get greetings!", "Good Afternoon, Jane Doe!", greetings);
    }
}

부분적인 조롱을위한 "스파이"

@Spy 주석 (또는 메서드 )은 객체를 부분적으로 모의하는 데 사용할 수 있습니다. 이것은 클래스의 동작을 부분적으로 모의 할 때 유용합니다. 예를 들어 두 개의 다른 서비스를 사용하는 클래스가 있고 그 중 하나만 조롱하고 다른 서비스의 실제 구현을 사용한다고 가정합니다.

참고 사항 : 철학적으로는 실제 클래스를 통합하고 테스트중인 클래스를 완전하게 격리하지 않으므로이 클래스를 "순수한 단위 테스트"로 간주하지는 않습니다. 그럼에도 불구하고 이것은 실제 세계에서 실제로 유용 할 수 있으며 실제 DAO를 사용할 수 있도록 메모리 데이터베이스 구현에서 일부를 사용하여 데이터베이스를 모의 할 때 자주 사용합니다.

Class under test:
public class GreetingsService { // class to be tested in isolation
    private UserService userService;
    private AppService appService;

    public GreetingsService(UserService userService, AppService appService) {
        this.userService = userService;
        this.appService = appService;
    }

    public String getGreetings(int userId, LocalTime time) { // the method under test
        StringBuilder greetings = new StringBuilder();
        String timeOfDay = getTimeOfDay(time.getHour());
        greetings.append("Good ").append(timeOfDay).append(", ");
        greetings.append(userService.getFirstName(userId)) // this call will be mocked
                .append(" ")
                .append(userService.getLastName(userId)) // this call will be mocked
                .append("!");
        greetings.append(" Welcome to ")
                .append(appService.getAppName()) // actual method call will be made
                .append(".");
        return greetings.toString();
    }

    private String getTimeOfDay(int hour) { // private method doesn't need to be unit tested
        if (hour >= 0 && hour < 12)
            return "Morning";
        else if (hour >= 12 && hour < 16)
            return "Afternoon";
        else if (hour >= 16 && hour < 21)
            return "Evening";
        else if (hour >= 21 && hour < 24)
            return "Night";
        else
            return null;
    }
}

이 인터페이스의 동작은 조롱받을 것입니다.

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

UserService 의 실제 구현을 가정합니다.

public class UserServiceImpl implements UserService {
    @Override
    public String getFirstName(int userId) {
        String firstName = "";
        // some logic to get user's first name
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return firstName;
    }

    @Override
    public String getLastName(int userId) {
        String lastName = "";
        // some logic to get user's last name
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return lastName;
    }
}

이 인터페이스의 동작은 조롱을받지 않습니다.

public interface AppService {
    String getAppName();
}

AppService 실제 구현을 가정합니다.

public class AppServiceImpl implements AppService {
    @Override
    public String getAppName() {
        // assume you are reading this from properties file
        String appName = "The Amazing Application";
        return appName;
    }
}

Mockito의 Junit 테스트 :

public class GreetingsServiceTest {
    @Mock
    private UserServiceImpl userService; // this class will be mocked
    @Spy
    private AppServiceImpl appService; // this class WON'T be mocked
    @InjectMocks
    private GreetingsService greetingsService = new GreetingsService(userService, appService);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGetGreetings_morning() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(99)).thenReturn("John");
        when(userService.getLastName(99)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(99, LocalTime.of(0, 45));
        Assert.assertEquals("Failed to get greetings!", "Good Morning, John Doe! Welcome to The Amazing Application.", greetings);
    }

    @Test
    public void testGetGreetings_afternoon() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(11)).thenReturn("Jane");
        when(userService.getLastName(11)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(11, LocalTime.of(13, 15));
        Assert.assertEquals("Failed to get greetings!", "Good Afternoon, Jane Doe! Welcome to The Amazing Application.", greetings);
    }
}

조롱 된 객체에 비공개 필드 설정

테스트중인 클래스에서 생성자를 통해 액세스 할 수없는 일부 비공개 필드가있을 수 있습니다. 그런 경우 리플렉션을 사용하여 이러한 속성을 설정할 수 있습니다. 이것은 JUnit 테스트에서 발췌 한 내용입니다.

@InjectMocks
private GreetingsService greetingsService = new GreetingsService(); // mocking this class

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
    String someName = "Some Name";
    ReflectionTestUtils.setField(greetingsService, // inject into this object
        "name", // assign to this field
        someName); // object to be injected
}

단순화하기 위해 Sptring의 ReflectionTestUtils.setField(Object targetObject, String name, Object value) 메소드 를 사용하고 있습니다 만, 기존의 Java Reflection을 사용하여 동일한 작업을 수행 할 수 있습니다.



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