모르지 않다는 것은 아는것과 다르다.

Junit

Mockito

채마스 2022. 2. 27. 01:41

Mockito 란?

  • Mock: 진짜 객체와 비슷하게 동작하지만 프로그래머가 직접 그 객체의 행동을 관리하는 객체다.
  • Mockito: Mock 객체를 쉽게 만들고 관리하고 검증할 수 있는 방법을 제공한다.
  • 테스트를 작성하는 자바 개발자 50%+ 사용하는 Mock 프레임워크다.



Mock 객체 생성

  @ExtendWith(MockitoExtension.class)
  class StudyServiceTest {

    @Mock
    MemberService memberService;

    @Mock
    StudyRepository studyRepository;

    @Test
    void createStudyService() {
      StudyService studyService = new StudyService(memberService, studyRepository);

      assertNotNull(studyService);
    }
  }
  • @Mock 을 사용해서 위와 같이 Mock 객체를 생성할 수 있다.
  @Test
    void createStudyService(@Mock MemberService memberService,
                            @Mock StudyRepository studyRepository) {

        StudyService studyService = new StudyService(memberService, studyRepository);
        assertNotNull(studyService);
    }
  • 위와 같이 매개변수에 설정해서 해당 메서드에만 적용시킬 수 있다.



Mock 객체 Stubbing

  @ExtendWith(MockitoExtension.class)
  class StudyServiceTest {

      @Test
      void createNewStudy(@Mock MemberService memberService,
                          @Mock StudyRepository studyRepository) {

          StudyService studyService = new StudyService(memberService, studyRepository);
          assertNotNull(studyService);

          Member member = new Member();
          member.setId(1L);
          member.setEmail("newleader95@gmail.com");

          when(memberService.findById(any()))
                  .thenReturn(Optional.of(member))
                  .thenThrow(new RuntimeException())
                  .thenReturn(Optional.empty());

          Optional<Member> byId = memberService.findById(1L);
          assertEquals("newleader95@gmail.com", byId.get().getEmail());

          assertThrows(RuntimeException.class, () -> {
              memberService.findById(2L);
          });

          assertEquals(Optional.empty(), memberService.findById(3L));
      }

  }
  • 특정한 매개변수를 받은 경우 특정한 값을 리턴하거나 예뢰를 던지도록 만들 수 있다.
  • Void 메소드 특정 매개변수를 받거나 호출된 경우 예외를 발생 시킬 수 있다.
  • 메소드가 동일한 매개변수로 여러번 호출될 때 각기 다르게 행동호도록 조작할 수도 있다.



Mock 객체 확인

  • Mock 객체가 어떻게 사용이 됐는지 확인할 수 있다.
  • 예시는 아래와 같다.
  @ExtendWith(MockitoExtension.class)
  class StudyServiceTest {

      @Mock MemberService memberService;
      @Mock StudyRepository studyRepository;

      @Test
      void createNewStudy() {
          StudyService studyService = new StudyService(memberService, studyRepository);
          assertNotNull(studyService);

          Member member = new Member();
          member.setId(1L);
          member.setEmail("newleader95@gmail.com");

          Study study = new Study(10, "테스트");

          when(memberService.findById(1L)).thenReturn(Optional.of(member));
          when(studyRepository.save(study)).thenReturn(study);

          studyService.createNewStudy(1L, study);
          assertEquals(member, study.getOwner());

          verify(memberService, times(1)).notify(study);
      }
  }
  • 특정 메소드가 특정 매개변수로 몇번 호출 되었는지, 최소 한번은 호출 됐는지, 전혀 호출되지 않았는지 확인할 수 있다.
  verify(memberService, times(1)).notify(study);
  verify(memberService, times(1)).notify(member);
  verify(memberService, never()).validate(any());
  • 위와 같이 어떤 순서대로 호출했는지 확인할 수 있다.
  • 이외에도 다양한 기능들을 확인할 수 있다.



Mockito BDD 스타일 API

  • BDD : 애플리케이션이 어떻게 "행동"해야 하는지에 대한 공통된 이해를 구성하는 방법으로, TDD에서 창안됐다.
  • Mockito는 BddMockito라는 클래스를 통해 BDD 스타일의 API를 제공한다.
  • Given -> When -> Then
  @ExtendWith(MockitoExtension.class)
  class StudyServiceTest {

      @Mock MemberService memberService;
      @Mock StudyRepository studyRepository;

      @Test
      void createNewStudy() {
          // Given
          StudyService studyService = new StudyService(memberService, studyRepository);
          assertNotNull(studyService);
          Member member = new Member();
          member.setId(1L);
          member.setEmail("newleader95@gmail.com");
          Study study = new Study(10, "테스트");
          given(memberService.findById(1L)).willReturn(Optional.of(member));
          given(studyRepository.save(study)).willReturn(study);

          // When 
          studyService.createNewStudy(1L, study);

          // Then
          assertEquals(member, study.getOwner());

          then(memberService).should(times(1)).notify(study);
          then(memberService).shouldHaveNoMoreInteractions();
      }
  }




REFERENCES

  • 백기선님의 더 자바, 애플리케이션을 테스트하는 다양한 방법

'Junit' 카테고리의 다른 글

Repository 단위테스트  (0) 2022.02.27
MockMvc  (0) 2022.02.27
Junit5 애노테이션 비교  (0) 2022.02.27
# Junit 5 기본 애노테이션  (0) 2022.02.27
Controller 단위테스트  (0) 2022.02.27