ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2. Mockito
    Test/더 자바, 테스트하는 다양한 방법 2022. 11. 11. 18:12

    Mockito 소개

    - Mock : 진짜 객체와 비슷하게 동작하지만 프로그래머가 직접 그 객체의 행동을 관리하는 객체

    - Mockito : Mock 객체를 쉽게 만들고 관리하고 검증할 수 있는 방법을 제공

     

    Mockito 시작하기

    - 스프링부트 2.2+ 프로젝트 생성시 spring-boot-starter-test에서 자동으로 Mockito 추가해 줌

        ㆍmockito-core

        ㆍmockito-junit-jupiter

    - 다음 세 가지만 알면 Mock을 활용한 테스트를 쉽게 작성할 수 있다.

        ㆍMock을 만드는 방법

        ㆍMock이 어떻게 동작해야 하는지 관리하는 방법

        ㆍMock의 행동을 검증하는 방법

     

    Mock 객체 만들기

    - Mockito.mock() 메소드로 만드는 방법

    @Test
    void createStudyService() {
        MemberService memberService = Mockito.mock(MemberService.class);
        StudyRepository studyRepository = Mockito.mock(StudyRepository.class);
    
        StudyService studyService = new StudyService(memberService, studyRepository);
    
        assertNotNull(studyService);
    }

    - @Mock 애노테이션으로 만드는 방법

        ㆍJUnit 5 extension 으로 MockitoExtension을 사용해야 한다.

        ㆍ필드

        ㆍ메소드 매개변수

    @ExtendWith(MockitoExtension.class)
    class StudyServiceTest {
    
        @Mock
        MemberService memberService;
    
        @Mock
        StudyRepository studyRepository;
    }
    @ExtendWith(MockitoExtension.class)
    class StudyServiceTest {
        @Test
        void createStudyService(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
            StudyService studyService = new StudyService(memberService, studyRepository);
            assertNotNull(studyService);
        }
    }

     

    Mock 객체 Stubbing

    - 모든 Mock 객체의 행동

        ㆍNull을 리턴한다. (Optional 타입은 Optional.empty 리턴)

        ㆍPrimitive 타입은 기본 Primitive 값

        ㆍ콜렉션은 비어있는 콜렉션

        ㆍVoid 메소드는 예외를 던지지 않고 아무런 일도 발생하지 않는다

    - Mock 객체를 조작해서

        ㆍ특정한 매개변수를 받은 결우 특정한 값을 리턴하거나 예외를 던지도록 만들 수 있다

    Mockito.when(memberService.findById(Mockito.any())).thenReturn(Optional.of(member));   // memberService.findById() 호출되면 Optional.of(member) 리턴

        ㆍVoid 메소드 특정 매개변수를 받거나 호출된 경우 예외를 발생 시킬 수 있다

    Mockito.when(memberService.findById(1L)).thenThrow(new RuntimeException()); // 리턴타입이 있을 때 예외던지기
    Mockito.doThrow(new IllegalArgumentException()).when(memberService).validate(1L);   // 리턴타입이 void 일때
    assertThrows(IllegalArgumentException.class, () -> {
        memberService.validate(1L);
    });

        ㆍ메소드가 동일한 매개변수로 여러번 호출될 때 각기 다르게 행동하도록 조작할 수 있다.

    Mockito.when(memberService.findById(Mockito.any()))
            .thenReturn(Optional.of(member))
            .thenThrow(new RuntimeException())
            .thenReturn(Optional.empty());
    assertEquals("phm@email.com",memberService.findById(1L).get().getEmail());
    assertThrows(RuntimeException.class, () -> {
        memberService.findById(2L);
    });
    assertEquals(Optional.empty(), memberService.findById(3L));

     

    Mock 객체 확인

    - Mock 객체가 어떻게 사용이 됐는지 확인할 수 있다

        ㆍ특정 메소드가 특정 매개변수로 몇번 호출 되었는지, 최소 한번은 호출 됐는지, 전혀 호출되지 않았는지

    Mockito.verify(memberService, Mockito.times(1)).notify(study);  // memberService.notify(study)의 호출횟수 확인
    Mockito.verify(memberService, Mockito.never()).validate(Mockito.any());  // memberService.validate() 은 호출 X

        ㆍ어떤 순서대로 호출했는지

    // 순서 확인
    InOrder inOrder = Mockito.inOrder(memberService);
    inOrder.verify(memberService).notify(study);
    inOrder.verify(memberService).notify(member);

        ㆍ특정 시간 이내에 호출했는지

        ㆍ특정 시점 이후에 아무 일도 벌어지지 않았는지

    // 액션이 없어야 한다는 것을 테스트
    Mockito.verifyNoInteractions(memberService);

     

    Mockito BDD 스타일 API

    - BDD : 애플리케이션이 어떻게 "행동"해야 하는지에 대한 공통된 이해를 구성하는 방법으로, TDD에서 창안했다

    - 행동에 대한 스펙

        ㆍTitle

        ㆍNarrative

              º As a / I want / so that 

        ㆍAcceptance criteria

              º Given / When Then

    - Mockito는 BddMockito라는 클래스를 통해 BDD 스타일의 API를 제공한다

        @Test
        @DisplayName("BDD 스타일 Mockito API")
        void BddMockitoAPI() {
            // Given
            StudyService studyService = new StudyService(memberService, studyRepository);
            assertNotNull(studyService);
    
            Member member = new Member();
            member.setId(1L);
            member.setEmail("phm@email.com");
    
            Study study = new Study(10, "테스트");
    
    //        Mockito.when(memberService.findById(1L)).thenReturn(Optional.of(member));
    //        Mockito.when(studyRepository.save(study)).thenReturn(study);
            BDDMockito.given(memberService.findById(1L)).willReturn(Optional.of(member));
            BDDMockito.given(studyRepository.save(study)).willReturn(study);
    
            // When
            studyService.createNewStudy(1L, study);
    
            // Then
            assertEquals(member, study.getOwnerId());
    //        Mockito.verify(memberService, Mockito.times(1)).notify(study);
            BDDMockito.then(memberService).should(Mockito.times(1)).notify(study);
    //        Mockito.verifyNoInteractions(memberService);
            BDDMockito.then(memberService).shouldHaveNoMoreInteractions();
        }

    'Test > 더 자바, 테스트하는 다양한 방법' 카테고리의 다른 글

    1. JUnit5  (0) 2022.10.27

    댓글

Designed by Tistory.