MOCKITO

이진우·2021년 6월 9일
0

1. stub

메서드를 호출하면 미리 정의된 답변을 줌

  • 위키피디아 : 스텁은 기존 코드(예를 들어 원격 머신의 프로시저)를 흉내 내거나 아직 개발되지 않은 코드를 임시로 대치하는 역할을 수행한다.
  • Mocks Aren't Stubs : Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test.
  • canned answer : 미리 준비된 답변
  • Stub은 테스트 중에 이루어진 호출에 대해 미리 준비된 답변을 제공하며, 일반적으로 테스트를 위해 프로그래밍 된 내용 이외의 항목에는 전혀 응답하지 않습니다.

2. javadoc

https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html

1. Let's verifiy some behavior!

몇 가지의 동작을 확인하자

  • import static org.mockito.Mockito.mock; 은 static으로 선언하는 것이 코드가 깔끔해진다.
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

@DisplayName("Mockito JavaDoc 3.10.0 API")
public class MockitoJavaDoc {
    @Test
    @DisplayName("1. Let's verify some behaviour!")
    void step_01_test(){
        //mock 생성
        List mockedList = mock(List.class);

        //mock 객체 사용
        mockedList.add("test1");
        mockedList.clear();

        //verification(확인)
        verify(mockedList).add("test1");
        mockedList.clear();
    }
}

2. How about some stubbing?

Stubbing은 어떻게 하지?

1) Step 1 : mock 객체 선언 (interface도 가능)

2) Step 2 : stubbing → stubbing 이후 method호 출시 일정한 값을 반환

3) Step 3 : mock은 null, primitive / primitive value 또는 비어있는 collection을 적절하게 반환 → 999번째 값을 반환해도 Exception이 아닌 null을 반환

4) Step 4 : verify로 검증 가능하다. 만약 stubbing 하지 않은 값을 호출한다면 케이스는 실패한다.


import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.LinkedList;
import java.util.NoSuchElementException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@DisplayName("Mockito JavaDoc 3.10.0 API")
public class MockitoJavaDocStep02 {

    @Test
    @DisplayName("2. How about some stubbing?")
    void step_02_test(){
        //step1
        LinkedList mockedList = mock(LinkedList.class);

        //step2 stubbing
        when(mockedList.get(0)).thenReturn("test2");
        when(mockedList.get(1)).thenThrow(new NoSuchElementException());

        //step3
        assertThat(mockedList.get(0)).isEqualTo("test2");
        assertThatThrownBy(() -> mockedList.get(1))
                .isInstanceOf(NoSuchElementException.class);
        assertThat(mockedList.get(999)).isNull();

        //step4
        verify(mockedList).get(1);
        verify(mockedList).get(999);
        verify(mockedList).get(0);
        //verify(mockedList).get(2);
    }
}

3. Argument matchers

Argument matcher 사용법

  • Step 1 : mock 객체 선언 (interface도 가능)
  • Step 2 : stubbing
    • anyInt()로 어떤 int 값이 넘어와도 "Integer" 문자열이 리턴 가능하도록 세팅
    • argThat()을 통해 사용자 정의 argument 검증 가능 → ArgumentMatcher<T>를 상속
    • anyObject(), eq() 등도 있다.
  • Step 3 : verify를 진행할 method 호출 (호출 하지 않으면 LinkedList에 담기지 않음)
  • Step 4 : verifiy로 검증 → 기본적으로 Java equals() 검증 사용
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatcher;
import java.util.LinkedList;
import java.util.List;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@DisplayName("Mockito JavaDoc 3.10.0 API")
public class MockitoJavaDocStep03 {

    class IsLengthGreaterThanOneArgument implements ArgumentMatcher<List> {
        @Override
        public boolean matches(List list) {
            return String.valueOf(list.get(anyInt())).length() > 1;
        }
    }

    @Test
    @DisplayName("3. Argument matchers")
    void step_03_test() {
        //step1
        LinkedList mockedList = mock(LinkedList.class);

        //step2
        when(mockedList
                .get(anyInt()))
                .thenReturn("Integer");
        when(mockedList
                .contains(argThat(new IsLengthGreaterThanOneArgument())))
                .thenReturn(true);

        //step3
        mockedList.get(1);
        mockedList.get(999);
        mockedList.get(0);
        mockedList.get(2);

        //step4
        verify(mockedList).get(1);
        verify(mockedList).get(999);
        verify(mockedList).get(0);
        verify(mockedList).get(2);
    }
}

4. Verifying exact number of invocations / at least x / never

Method 호출 횟수 계산하기

  • Step 1 : mock 객체 선언 (interface도 가능)
  • Step 2 : stubbing
    • "once" : 1 회 add
    • "twice" : 2 회 add
    • "three times" : 3회 add
  • Step 3 : verify에 times로 호출 횟수 검증
    • times(int) - 지정한 횟수 만큼 호출 되었는 지 검증 → 기본 값은 times(1)
  • Step 4 : verifiy에 제공 함수를 통해 호출 횟수 검증
    • never() : 호출되지 않았는지 여부 검증
    • atLeastOnce() : 적어도 한번은 호출 되었는 지 검증
    • atLeast(int) : 적어도 지정한 횟수 만큼 호출 되었는 지 검증
    • atMost(int) : 최대 지정한 횟수 만큼 호출 되었는 지 검증
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.LinkedList;
import java.util.List;

import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.atMostOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep04 {
    @Test
    @DisplayName("4. Verifying exact number of invocations / at least x / never")
    void step_04_test(){
        //step1
        LinkedList mockedList = mock(LinkedList.class);

        //step2
        mockedList.add("once");

        mockedList.add("twice");
        mockedList.add("twice");

        mockedList.add("three times");
        mockedList.add("three times");
        mockedList.add("three times");

        //step3
        verify(mockedList).add("once");
        verify(mockedList, times(1)).add("once");
        verify(mockedList, times(2)).add("twice");
        verify(mockedList, times(3)).add("three times");

        //step4
        verify(mockedList, atMostOnce()).add("once");
        verify(mockedList, atLeastOnce()).add("three times");
        verify(mockedList, atLeast(2)).add("three times");
        verify(mockedList, atMost(5)).add("three times");
    }
}

5. Stubbing void methods with exceptions

void Method의 Stubbing 방법

  • 방법 1. doThrow

    • Step 1 : mock 객체 선언 (interface도 가능)

    • Step 2 : stubbing → anyInt()로 어떠한 값이 들어와도 RuntimeException 발생

    • Step 3 : assertThatThrownBy로 mockedList에서 조회 시 RuntimeException Throw 발생 확인

      import org.junit.jupiter.api.DisplayName;
      import org.junit.jupiter.api.Test;
      import java.util.List;
      
      import static org.assertj.core.api.Assertions.assertThatThrownBy;
      import static org.mockito.ArgumentMatchers.anyInt;
      import static org.mockito.Mockito.doThrow;
      import static org.mockito.Mockito.mock;
      
      @DisplayName("Mockito JavaDoc 3.10.0 API")
      class MockitoJavaDocStep05 {
          @Test
          @DisplayName("5. Stubbing void methods with exceptions")
          void step_05_test(){
              //step1
              List mockedList = mock(List.class);
      
              //step2
              doThrow(new RuntimeException()).when(mockedList).get(anyInt());
      
              //step3
              assertThatThrownBy(() -> mockedList.get(1))
                      .isInstanceOf(RuntimeException.class);
              assertThatThrownBy(() -> mockedList.get(1001))
                      .isInstanceOf(RuntimeException.class);
          }
      }
  • 방법 2. doNothing

    • Step 1 : mock 객체 선언 (interface도 가능)

    • Step 2 : stubbing → doNothing으로 반환값 없음으로 설정

    • Step 3 : method 실행

    • Step 4 : verify 검증

      import org.junit.jupiter.api.DisplayName;
      import org.junit.jupiter.api.Test;
      import java.util.List;
      
      import static org.assertj.core.api.Assertions.assertThatThrownBy;
      import static org.mockito.ArgumentMatchers.anyInt;
      import static org.mockito.Mockito.doThrow;
      import static org.mockito.Mockito.mock;
      
      @DisplayName("Mockito JavaDoc 3.10.0 API")
      class MockitoJavaDocStep05 {
      		@Test
          @DisplayName("5. Stubbing void methods with exceptions")
          void step_05_2_test(){
              //step1
              List mockedList = mock(List.class);
      
              //step2
              doNothing().when(mockedList).clear();
      
              //step3
              mockedList.clear();
      
              //step3
              verify(mockedList).clear();
          }
      }

6. Verification in order

호출 순서 검증

  • Step 1 : mock 객체 선언 (interface도 가능)
  • Step 2 : stubbing
  • Step 3 : InOrder에 mock 전달
  • Step 4 : InOrder를 통해 메소드 호출 순서 검증
  • Step 5 : mock 객체 선언 (interface도 가능) → 2개의 다른 객체
  • Step 6 : stubbing
  • Step 7 : InOrder에 두개의 mock 객체 전달
  • Step 8 : InOrder를 통해 메소드 호출 순서 검증 → 2개의 다른 객체도 검증이 가능
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.InOrder;
import java.util.List;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep06 {
    @Test
    @DisplayName("6. Verification in order")
    void step_06_test(){
        //step1
        List singleMock = mock(List.class);

        //step2
        singleMock.add("was added first");
        singleMock.add("was added second");

        //step3
        InOrder inOrder = inOrder(singleMock);

        //step4
        inOrder.verify(singleMock).add("was added first");
        inOrder.verify(singleMock).add("was added second");

        //step5
        List firstMock = mock(List.class);
        List secondMock = mock(List.class);

        //step6
        firstMock.add("was called first");
        secondMock.add("was called second");

        //step7
        InOrder inOrderTwo = inOrder(firstMock, secondMock);

        //step8
        inOrderTwo.verify(firstMock).add("was called first");
        inOrderTwo.verify(secondMock).add("was called second");
    }
}

7. Making sure interaction(s) never happened on mock

다수의 객체가 사용되지 않았음을 검증

  • Step 1 : mock 객체 선언 (interface도 가능)
  • Step 2 : verifyNoInteraction 로 객체의 사용 유무 검증 → verifyZeroInteractionsdeprecated
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.~~verifyZeroInteractions~~;

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep07 {
    @Test
    @DisplayName("7. Making sure interaction(s) never happened on mock")
    void step_07_test(){
        //step1
        List mockListOne = mock(List.class);
        List mockListTwo = mock(List.class);

        //step2
        //~~verifyZeroInteractions~~(mockListOne,mockListTwo);
        verifyNoInteractions(mockListOne, mockListTwo);
    }
}

8. Finding redundant invocations

중복 호출 찾기 (과도한 사용은 유지 관리가 어려움)

  • Step 1 : mock 객체 선언 (interface도 가능)
  • Step 2 : mockList에 add를 두번 실행 → "one", "two" 추가
  • Step 3 : verify로 add("one") 실행검증 → 1회 실행
  • Step 4 : verifyNoMoreInteractions 으로 추가 검증 실행여부 확인 → add("two")에 대한 검증은 수행되지 않음 → Fail
  • 만약 "two"에 대한 verify가 추가 된다면 → Success
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep08 {
    @Test
    @DisplayName("8. Finding redundant invocations")
    void step_08_test(){
        //step1
        List mockList = mock(List.class);

        //step2 stubbing
        mockList.add("one");
        mockList.add("two");

        //step3
        verify(mockList).add("one");
				//verify(mockList).add("two");

        //step4
        verifyNoMoreInteractions(mockList);
    }
}

9. Shorthand for mocks creation - @Mock annotation

빠르게 mock 생성하기 (@Mock annotation)

  1. Minimizes repetitive mock creation code. (반복적인 mock의 생성 최소화)
  2. Makes the test class more readable. (가독성 증가)
  3. Makes the verification error easier to read because the field name is used to identify the mock. (필드 명으로 mock을 식별하기 때문에 에러에 대한 파악이 더 쉽다.)
  4. This needs to be somewhere in the base class or a test runner. (반드시 작성해 주어야함) → 내장된 runner 사용 가능(MockitoJUnitRunner) / rule은 MockitoRule
  5. **MockitoAnnotations.initMocksdeprecated 됨**
MockitoAnnotations.openMocks(this);
//MockitoAnnotations.~~initMocks~~(this);
  • Step 1 : MockitoAnnotations.openMocks(this) Runner 사용 → Test Class의 Person 선언부에 @Mock Annotation 삽입
  • Step 2 : stubbing → when을 통해 Person의 getName 값 stubbing
  • Step 3 : assertThat을 통해 getName 검증
  • Step 4 : verify 확인
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class Person {
    private Long id;
    private String name;

    public Person() {
    }

    public Person(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep09 {
    @Mock
    private Person person;

    @Test
    @DisplayName("9. Shorthand for mocks creation - @Mock annotation")
    void step_09_test(){
        //step1
        MockitoAnnotations.openMocks(this);

        //step2
        when(person.getName()).thenReturn("psjw");

        //step3
        assertThat(person.getName()).contains("psjw");

        //step4
        verify(person).getName();
    }
}

10. Stubbing consecutive calls (iterator-style stubbing)

연속적으로 다른 stubbing 하기

  • Step 1 : mock 객체 선언 (interface도 가능)
  • Step 2 : Stubbiing → thenReturn으로 2회, thenThrow 1회 Stub
  • Step 3 : return 세팅 순으로 호출하여 데이터 검증
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep10 {

    @Test
    @DisplayName("10. Stubbing consecutive calls (iterator-style stubbing)")
    void step_10_test(){
        //step1
        List<String> mockedList = mock(List.class);

        //step2
        when(mockedList.get(anyInt()))
                .thenReturn("one")
                .thenReturn("two")
                .thenThrow(new RuntimeException());

        //step3
        assertThat(mockedList.get(0)).isEqualTo("one");
        assertThat(mockedList.get(0)).isEqualTo("two");
        assertThatThrownBy(() -> mockedList.get(0))
                .isInstanceOf(RuntimeException.class);
    }
}

11. Stubbing with callbacks

Answer로 Callback을 Stubbing 함

  • Step 1 : mock 객체 선언 (interface도 가능)
  • Step 2 : Stubbiing → thenAnswer를 통해 Callback 함수 정의 → Lambda 식으로도 가능
  • Step 3 : return 값 점검
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.Arrays;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep11 {

    @Test
    @DisplayName("11. Stubbing with callbacks")
    void step_11_test() {
        //step1
        List<String> mockedList = mock(List.class);

        //step2
        when(mockedList.get(anyInt()))
                .thenAnswer(new Answer<Object>() {
                    @Override
                    public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                        Object[] objects = invocationOnMock.getArguments();
                        Object mock = invocationOnMock.getMock();
                        return  "called with arguments : " + Arrays.toString(objects);
                    }
                });
        /*
        when(mockedList.get(anyInt()))
                .thenAnswer(invocationOnMock -> {
                    Object[] objects = invocationOnMock.getArguments();
                    Object mock = invocationOnMock.getMock();
                    return  "called with arguments : " + Arrays.toString(objects);
                });
        */

        //step3
        assertThat(mockedList.get(0)).isEqualTo("called with arguments : [0]");
    }
}

12. doReturn()|doThrow()| doAnswer()|doNothing()|doCallRealMethod() family of methods

doReturn(), doThrow(), doAnswer(), doNothing(), doCallRealMethod() 은 when() 함수에서 호출 됨

[doReturn(Object)](https://javadoc.io/static/org.mockito/mockito-core/3.10.0/org/mockito/Mockito.html#doReturn-java.lang.Object-)

[doThrow(Throwable...)](https://javadoc.io/static/org.mockito/mockito-core/3.10.0/org/mockito/Mockito.html#doThrow-java.lang.Throwable...-)

[doThrow(Class)](https://javadoc.io/static/org.mockito/mockito-core/3.10.0/org/mockito/Mockito.html#doThrow-java.lang.Class-)

[doAnswer(Answer)](https://javadoc.io/static/org.mockito/mockito-core/3.10.0/org/mockito/Mockito.html#doAnswer-org.mockito.stubbing.Answer-)

[doNothing()](https://javadoc.io/static/org.mockito/mockito-core/3.10.0/org/mockito/Mockito.html#doNothing--)

[doCallRealMethod()](https://javadoc.io/static/org.mockito/mockito-core/3.10.0/org/mockito/Mockito.html#doCallRealMethod--)

13. Spying on real objects

spy 메서드를 통해 실제 객체에 대한 mock을 생성

  1. spy 객체를 사용하면 실제 매서드 호출됨 (not stubbing)
  2. 그렇다고 실제 객체의 호출을 위임하는게 아니라 복사본을 생성
  3. 그러므로 실제 객체에 영향은 없다
  4. final Method를 mock하지 않음
  • Step 1 : ArrayList객체를 생성 후 spy 객체 생성
  • Step 2 : Stubbiing → when을 먼저 사용하면 예외 발생 → doReturn을 먼저 사용해야 됨
  • Step 3 : spy객체의 method실행
  • Step 4 : return 값 점검 → spy 객체는 "one'을 return → 실제 mockedList 객체에서는 Exception 발생
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep13 {

    @Test
    @DisplayName("13. Spying on real objects")
    void step_13_test() {
        //step1
        final List mockedList = new ArrayList();
        final List spy = spy(mockedList);

        //step2
        //when(spy.size()).thenReturn(100);
        doReturn("one").when(spy).get(0);

        //step3
        spy.add("one");
        spy.add("two");

        //step4
        assertThat(spy.get(0)).isEqualTo("one");
				assertThatThrownBy(() -> mockedList.get(0))
                .isInstanceOf(IndexOutOfBoundsException.class);
    }
}

14. Changing default return values of unstubbed invocations (Since 1.7)

Stub 되지 않은 Method를 호출할 때 default 값을 지정

  1. 일반적으로 사용하지 않지만 legacy 시스템 작업에도 도움이 될 수 있음
Foo mock = mock(Foo.class, Mockito.RETURNS_SMART_NULLS);
Foo mockTwo = mock(Foo.class, new YourOwnAnswer());
  • Step 1 : mock 객체를 생성 후 Name 필드의 반환값이 Null인지 체크
  • Step 2 : RETURNS_SMART_NULLS 를 활용하여 반환값이 Null이 아니고 Name 필드는 ""으로 반환 확인
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.RETURNS_SMART_NULLS;
import static org.mockito.Mockito.mock;

class Person2 {
    private Long id;
    private String name;

    public Person2() {
    }

    public Person2(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep14 {

    @Test
    @DisplayName("14. Changing default return values of unstubbed invocations (Since 1.7)")
    void step_14_test() {
        //step1
        Person2 mockedP = mock(Person2.class);
        assertThat(mockedP.getName()).isNull();

        //step2
        Person2 mockedSmartP = mock(Person2.class, RETURNS_SMART_NULLS);
        assertThat(mockedSmartP.getName()).isNotNull();
        assertThat(mockedSmartP.getName()).isEqualTo("");
    }
}

15. Capturing arguments for further assertions (Since 1.8.0)

Capturing arguments를 통한 검증

  • Step 1 : mock 객체 선언 (interface도 가능)
  • Step 2 : add method 실행 → 2 회
  • Step 3 : ArgumentCaptorforClass(클래스) 메서드를 통해 String.class를 세팅하고, add의 input 값 capture() → "one", "two"
  • Step 4 : ArgumentCaptorallValues() 함수로 리스트로 반환 받음
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep15 {

    @Test
    @DisplayName("15. Capturing arguments for further assertions (Since 1.8.0)")
    void step_15_test() {
        //step1
        List mockedList = mock(List.class);

        //step2
        mockedList.add("one");
				mockedList.add("two");

        //step3
        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
        verify(mockedList, times(2)).add(argumentCaptor.capture());

        //step4
        final List<String> allValues = argumentCaptor.getAllValues();
        assertThat(allValues.get(0)).isEqualTo("one");
        assertThat(allValues.get(1)).isEqualTo("two");
    }
}

16. Real partial mocks (Since 1.8.0)

spy를 통해 partial mock을 사용할 수 있음.

  • Step 1 : spy() method로 partial mock 생성 가능
  • Step 2 : mock에 대해 선택적으로 partial mock 기능을 동작 시킬 수 있음
  • Step 3 : 실제 구현이 안전하다는 것을 확인 → 만약 실제 구현이 Exception or 특정 객체의 상태에 의존하면 문제가 있다.
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.LinkedList;
import java.util.List;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

class Person3 {
    private Long id;
    private String name;

    public Person3() {
    }

    public Person3(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep16 {

    @Test
    @DisplayName("16. Real partial mocks (Since 1.8.0)")
    void step_16_test() {
        //step1
        List list = spy(new LinkedList());

        //step2
        Person3 mock = mock(Person3.class);

        //step3
        when(mock.getName()).thenCallRealMethod();
    }
}

17. Resetting mocks (Since 1.8.0)

mock은 stubbing 초기화가 가능함

  • Step 1 : mock 객체 선언 (interface도 가능)
  • Step 2 : Stubbing
  • Step 3 : mock 결과확인 → mock stub 확인
  • Step 4 : mock reset
  • Step 5 : mock 결과 확인 → mock stub 초기화 확인 0건
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep17 {

    @Test
    @DisplayName("17. Resetting mocks (Since 1.8.0)")
    void step_17_test() {
        //step1
        List mock = mock(List.class);

        //step2
        when(mock.size()).thenReturn(10);
        mock.add(1);

        //step3
        assertThat(mock.size()).isEqualTo(10);

        //step4
        reset(mock);

        //step5
        assertThat(mock.size()).isEqualTo(0);
    }
}

18. Troubleshooting & validating framework usage (Since 1.8.0)

FAQ : https://github.com/mockito/mockito/wiki/FAQ

19. Aliases for behavior driven development (Since 1.8.0)

BDD(Behavior Driven Developmen)은 method에 기본으로 //given, //when, //then 을 주석을 사용

  • when을 이용한 구문이 BDD//given, //when, //then 주석에 맞지 않음 → stubbing은 given에 속함.
  • Step 1 : given → mock 객체 선언 및 given을 통해 stubbing
  • Step 2 : when → method 호출
  • Step 3 : then → return 결과 확인
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;

@DisplayName("Mockito JavaDoc 3.10.0 API")
class MockitoJavaDocStep19 {

    @Test
    @DisplayName("19. Aliases for behavior driven development (Since 1.8.0)")
    void step_19_test() {
        //step1 :  given
        List<String> mockedList = mock(List.class);
        given(mockedList.get(0)).willReturn("one");

           //when
        String value = mockedList.get(0);

        //then
        assertThat(value).isEqualTo("one");
        then(mockedList).should(times(1)).get(0);
    }
}
profile
시작이 반이다.

0개의 댓글