Mockito 시 뮬 레이 션 으로 자바 유닛 테스트 진행

14392 단어
모 키 토 가 뭐야?
홈 페이지:https://site.mockito.org/
Mockito is a mocking framework, JAVA - based library that is used for effective unit testing of JAVA applications. Mockito is used to mock interfaces so that a dummy functional can be added to a mock interface that can be used in unit testing.Mockito 는 유닛 테스트 에서 허구 적 인 방법 을 사용 할 수 있 도록 인 터 페 이 스 를 모 의 할 수 있다.
왜 시 뮬 레이 션 이 필요 합 니까?유닛 테스트 의 생각 은 우리 가 의존 을 테스트 하지 않 고 코드 를 테스트 해 야 한 다 는 것 이다.때때로 우 리 는 의지 하고 싶 지 않 거나 의지 할 준비 가 되 지 않 았 다 고 말 할 때 우 리 는 시 뮬 레이 션 이 필요 하 다.
기본 용법
  • mock() / @Mock: 시 뮬 레이 션 생 성
  • optionally specify how it should behave via Answer/MockSettings
  • when() / given() 시 뮬 레이 션 행 위 를 지정 합 니 다 (방법)
  • 기본 적 인 상황 에서 mock 대상 의 반환 값 을 호출 하 는 방법 은 기본 값 을 되 돌려 줍 니 다. 예 를 들 어 반환 null, 0 값 또는 false 등 입 니 다.
  • 같은 방법 과 매개 변 수 는 하나의 대 리 를 유일 하 게 확인한다.예 를 들 어 대리 get(int) 방법 은 매개 변수 가 각각 01 일 때의 서로 다른 행 위 를 할 수 있다.

  • spy() / @Spy: 일부 시 뮬 레이 션 을 실현 하면 진정한 방법 은 호출 되 지만 stubbing 과 verify
  • @InjectMocks: 자동 주입 @Spy 또는 @Mock 주해 의 속성
  • verify(): 방법 이 호출 되 었 는 지 검증 하고 몇 번 호출 되 었 습 니 다.
  • 유연 한 일치 파 라미 터 를 사용 할 수 있다. 예 를 들 어 any()
  • 매개 변 수 를 @Captor 통 해 캡 처 할 수 있 습 니 다

  • 구체 적 인 참조:https://static.javadoc.io/org.mockito/mockito-core/2.22.0/org/mockito/Mockito.html
    여기에서 maven 을 통 해 구축:
    
        
            junit
            junit
            4.12
            test
        
    
        
            org.mockito
            mockito-core
            2.22.0
            test
        
    
    

    1. 방법 이 호출 되 었 는 지 확인 하기 위해 verify 를 사용 합 니 다.
    import org.junit.Test;
    import java.util.List;
    import static org.mockito.Mockito.*;
    
    public class TestRunner {
    
        @Test
        public void Test1() {
            //       
            List mockedList = mock(List.class);
    
            //       
            mockedList.add("one");
            mockedList.clear();
    
            //     ,       
            verify(mockedList).add("one");
            verify(mockedList).clear();
        }
    }
    

    2. stubbing 존 근 을 어떻게 사용 합 니까?
    @Test
    public void Test2() {
        //         ,         
        LinkedList mockedList = mock(LinkedList.class);
    
        // stubbing   
        when(mockedList.get(0)).thenReturn("first");
        when(mockedList.get(1)).thenThrow(new RuntimeException());
    
        //    first
        System.out.println(mockedList.get(0));
    
        //    java.lang.RuntimeException
        System.out.println(mockedList.get(1));
    
        //    "null" because get(999) was not stubbed
        System.out.println(mockedList.get(999));
    }
    

    3. 매개 변수 일치
    예 를 들 어 우 리 는 anyInt() 를 사용 하여 임의의 정수 유형 과 일치 할 수 있다.더 많은 내장 matcher 와 사용자 정의 matcher 를 참조 하 십시오:https://static.javadoc.io/org.mockito/mockito-core/2.22.0/org/mockito/ArgumentMatchers.html
    @Test
    public void Test3() {
        //         ,         
        LinkedList mockedList = mock(LinkedList.class);
    
        // stubbing   ,      anyInt()      
        when(mockedList.get(anyInt())).thenReturn("element");
    
        //    element
        System.out.println(mockedList.get(999));
    
        //     ,       
        verify(mockedList).get(anyInt());
    }
    

    4. 검증 방법 이 호출 된 횟수
    @Test
    public void Test4() {
        //         ,         
        LinkedList mockedList = mock(LinkedList.class);
    
        //    mock
        mockedList.add("once");
    
        mockedList.add("twice");
        mockedList.add("twice");
    
        mockedList.add("three times");
        mockedList.add("three times");
        mockedList.add("three times");
    
        //            
        verify(mockedList).add("once");
        verify(mockedList, times(1)).add("once");
        verify(mockedList, times(2)).add("twice");
        verify(mockedList, times(3)).add("three times");
    
        //           
        verify(mockedList, never()).add("never happened");
    
        //            
        verify(mockedList, atLeastOnce()).add("three times");
        verify(mockedList, atLeast(2)).add("three times");
        verify(mockedList, atMost(5)).add("three times");
    }
    

    5. 검증 방법의 호출 순서
    @Test
    public void Test5() {
        List singleMock = mock(List.class);
    
        //    mock
        singleMock.add("was added first");
        singleMock.add("was added second");
    
        //    InOrder
        InOrder inOrder = inOrder(singleMock);
    
        //       "was added first",    "was added second"
        inOrder.verify(singleMock).add("was added first");
        inOrder.verify(singleMock).add("was added second");
    }
    

    6. @ Mock 주석 사용 하기
  • Minimizes repetitive mock creation code. Mock 생 성 간소화
  • Makes the test class more readable. 코드 의 가 독성 증가
  • Makes the verification error easier to read because the field name is used to identify the mock.
  • @Mock List mockedList;
    
    @Before
    public void initMocks() {
        MockitoAnnotations.initMocks(this);
    }
    
    @Test
    public void Test6() {
        //       
        mockedList.add("one");
        mockedList.clear();
    
        //     ,       
        verify(mockedList).add("one");
        verify(mockedList).clear();
    }
    

    7. stubbing 캐 시 루트 를 사용 하여 연속 호출 을 모 의 합 니 다.
    @Test
    public void Test7() {
        //       
        List mockedList = mock(List.class);
    
        when(mockedList.get(anyInt()))
                .thenThrow(new RuntimeException())
                .thenReturn("foo");
    
        //      ,    
        mockedList.get(1);
    
        //      ,   foo
        System.out.println(mockedList.get(1));
    }
    

    이렇게 사용 할 수 있 습 니 다: when(mock.someMethod("some arg")).thenReturn("one", "two", "three");8. 콜백 리 셋 이 있 는 stubbing 캐 시 를 사용 합 니 다.
    @Test
    public void Test8() {
        //       
        List mockedList = mock(List.class);
    
        when(mockedList.get(anyInt())).thenAnswer(
                new Answer() {
                    public Object answer(InvocationOnMock invocation) {
                        Object[] args = invocation.getArguments();
                        Object mock = invocation.getMock();
                        return "called with arguments: " + Arrays.toString(args);
                    }
                });
    
        //    "called with arguments: [1]"
        System.out.println(mockedList.get(1));
    }
    

    9. doReturn (), doThrow (), doAnswer (), doNothing (), doCallRealMethod () 를 사용 하여 빈 방법 void method
    @Test
    public void Test9() {
        //       
        List mockedList = mock(List.class);
    
        doThrow(new RuntimeException()).when(mockedList).clear();
    
        //      RuntimeException:
        mockedList.clear();
    }
    

    10. 진짜 대상 에서 스파이
    when you use the spy then the real methods are called (unless a method was stubbed). 스파이 를 사용 할 때 실제 대상 의 방법 은 stubbing 을 사용 하지 않 는 한 호출 됩 니 다. 예 를 들 어 when()...
    @Test
    public void Test10() {
        List list = new LinkedList();
        List spy = spy(list);
    
        //using the spy calls *real* methods
        spy.add("one");
        spy.add("two");
    
        //    one
        System.out.println(spy.get(0));
    
        //    2 
        System.out.println(spy.size());
    
        verify(spy).add("one");
        verify(spy).add("two");
    }
    

    11. 부분 시 뮬 레이 션 실현
    @Test
    public void Test11() {
        //       
        List mockedList = mock(LinkedList.class);
    
        //        ,      
        when(mockedList.size()).thenCallRealMethod();
    
        System.out.println(mockedList.size());
    }
    

    12. Mock 초기 화reset(mock); 방법 을 통 해 이전에 설 치 된 stubbing 을 초기 화 합 니 다.
    예시
    만약 에 우리 가 계산기 프로그램 CalculatorApplication 을 테스트 해 야 한다 고 가정 하지만 이 프로그램 은 CalculatorService 에 의존 하여 구체 적 인 계산 과정 을 실현 한다.코드 는 다음 과 같 습 니 다:
    public interface CalculatorService {
        public double add(double input1, double input2);
    
        public double subtract(double input1, double input2);
    
        public double multiply(double input1, double input2);
    
        public double divide(double input1, double input2);
    }
    
    public class CalculatorApplication {
        private CalculatorService calcService;
    
        public void setCalculatorService(CalculatorService calcService) {
            this.calcService = calcService;
        }
    
        public double add(double input1, double input2) {
            return calcService.add(input1, input2);
        }
    
        public double subtract(double input1, double input2) {
            return calcService.subtract(input1, input2);
        }
    
        public double multiply(double input1, double input2) {
            return calcService.multiply(input1, input2);
        }
    
        public double divide(double input1, double input2) {
            return calcService.divide(input1, input2);
        }
    }
    

    문제 가 생 겼 다. 테스트 할 때 우 리 는 CalculatorService 이 인터페이스의 구체 적 인 실현 류 가 없 을 것 이다. 예 를 들 어 CalculatorServiceImpl.따라서 우 리 는 테스트 할 때 이 인터페이스의 행동 을 모 의 해 야 한다.
    이때 우 리 는 mockito 를 사용 하여 행동 을 모 의 한다.
    mockito 는 주석 을 통 해 사용 할 수 있 습 니 다:
  • CalculatorService: 테스트 러 너 지정
  • @RunWith(MockitoJUnitRunner.class): Mark a field on which injection should be performed. 변 수 를 표시 합 니 다. 이 변 수 는 Mock 에 주 입 됩 니 다.예 를 들 어 @InjectMocks 는 하나의 CalculatorApplication 실현 에 주입 된다.
  • 주의: CalculatorService 에서 하나의 CalculatorApplication 방법 을 정의 하여 주입 해 야 합 니 다.

  • set: Mark a field as a mock. 변 수 를 표시 합 니 다. 이 변 수 는 Mock 입 니 다.예 를 들 어 @Mock.
  • Mock 을 표시 한 후 CalculatorService 를 통 해 이 Mock 의 행동 을 모 의 할 수 있다.


  • 예 는 다음 과 같다.
    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.InjectMocks;
    import org.mockito.Mock;
    import org.mockito.runners.MockitoJUnitRunner;
    
    import static org.mockito.Mockito.when;
    
    @RunWith(MockitoJUnitRunner.class)
    public class Mockito_Test {
        @InjectMocks
        CalculatorApplication calculatorApplication = new CalculatorApplication();
    
        @Mock
        CalculatorService calcService;
    
        @Test
        public void testAdd() {
            //    CalculatorService    
            when(calcService.add(10.0, 20.0)).thenReturn(30.00);
    
            //   
            Assert.assertEquals(calculatorApplication.add(10.0, 20.0), 30.0, 0);
        }
    }
    

    Mockito 원리
    참고: 리 버스 모드 의 클래식 - Mockito 디자인 분석
    우선, Mock 대상 이라는 것 은 본질 적 으로 프 록 시 모델 의 응용 이라는 것 을 알 아야 한다.프 록 시 모드 는 실제 대상 앞에서 프 록 시 대상 을 제공 하고 모든 실제 대상 에 대한 호출 은 프 록 시 대상 을 거 친 다음 에 프 록 시 대상 이 상황 에 따라 해당 하 는 처 리 를 결정 한다. 프 록 시 대상 은 자신의 처 리 를 직접 할 수도 있 고 실제 대상 에 대응 하 는 방법 을 사용 할 수도 있다. 프 록 시 대상 은 호출 자 에 게 투명 할 수도 있다.불투명 할 수도 있어.
    Mockito 는 자바 가 제공 하 는 Dynamic Proxy API 로 구현 된다.자바 의 동적 에이전트 에 대해 서 는 자바 동적 대 리 를 참조 하 십시오.
    Mockito 는 본질 적 으로 프 록 시 대상 호출 방법 전에 Stubbing 방식 으로 반환 값 을 설정 한 다음 에 실제 호출 할 때 프 록 시 대상 으로 미리 설 정 된 반환 값 을 되 돌려 줍 니 다.
    다음 코드 를 살 펴 보 겠 습 니 다.
    List mockedList = mock(List.class);
    
    //    mock       -      get       0     ,   "first"
    when(mockedList.get(0)).thenReturn("first");
    

    자바 의 프로그램 호출 은 스 택 형식 으로 이 루어 집 니 다. when 방법 when() 방법 에 대한 호출 은 보이 지 않 습 니 다.mockedList.get(0) 받 을 수 있 는 것 은 when() 의 반환 값 뿐이다.그래서 위의 코드 도 다음 과 같다.
    // stubbing   
    Object ret = mockedList.get(0);
    when(ret).thenReturn("first");
    
    mockedList.get(0) 방법의 소스 코드 를 보 세 요.
    public  OngoingStubbing when(T methodCall) {
        MockingProgress mockingProgress = ThreadSafeMockingProgress.mockingProgress();
        mockingProgress.stubbingStarted();
        OngoingStubbing stubbing = mockingProgress.pullOngoingStubbing();
        if (stubbing == null) {
            mockingProgress.reset();
            throw Reporter.missingMethodInvocation();
        } else {
            return stubbing;
        }
    }
    
    when() 인터페이스 에 어떤 방법 이 있 는 지 보 세 요.
    public interface OngoingStubbing {
        OngoingStubbing thenReturn(T var1);
    
        OngoingStubbing thenReturn(T var1, T... var2);
    
        OngoingStubbing thenThrow(Throwable... var1);
    
        OngoingStubbing thenThrow(Class extends Throwable> var1);
    
        OngoingStubbing thenThrow(Class extends Throwable> var1, Class... var2);
    
        OngoingStubbing thenCallRealMethod();
    
        OngoingStubbing thenAnswer(Answer> var1);
    
        OngoingStubbing then(Answer> var1);
    
         M getMock();
    }
    

    mock 대상 의 모든 방법 은 최종 적 으로 OngoingStubbingMockHandlerImpl 방법 으로 처리 되 며, 일부 코드 는 다음 과 같다.
    OngoingStubbingImpl ongoingStubbing = new OngoingStubbingImpl(this.invocationContainer);
    ThreadSafeMockingProgress.mockingProgress().reportOngoingStubbing(ongoingStubbing);
    StubbedInvocationMatcher stubbing = this.invocationContainer.findAnswerFor(invocation);
    StubbingLookupNotifier.notifyStubbedAnswerLookup(invocation, stubbing, this.invocationContainer.getStubbingsAscending(), (CreationSettings)this.mockSettings);
    Object ret;
    if (stubbing != null) {
        stubbing.captureArgumentsFrom(invocation);
    
        try {
            ret = stubbing.answer(invocation);
        } finally {
            ThreadSafeMockingProgress.mockingProgress().reportOngoingStubbing(ongoingStubbing);
        }
    
        return ret;
    } else {
        ret = this.mockSettings.getDefaultAnswer().answer(invocation);
        DefaultAnswerValidator.validateReturnValueFor(invocation, ret);
        this.invocationContainer.resetInvocationForPotentialStubbing(invocationMatcher);
        return ret;
    }
    
    handle 호출 의 기본 형식 은 when 이다. 이때 when(mock.doSome()) 는 위의 문 구 를 촉발 시 킬 수 있다. mock.doSome() 는 한 방법 에 대해 말뚝 을 박 는 포장 을 하고 있다 고 밝 혔 다. OngoingStubbingImpl 는 한 mock 대상 의 집사 에 해당 하 며 mock 대상 방법의 호출 을 기록 하고 있다.
    인용: Mockito Tutorial 반 모드 의 고전 - Mockito 디자인 분석 Mockito 소스 코드 분석

    좋은 웹페이지 즐겨찾기