Spring Boot/Mockito

[Mockito] Mock 객체 Stubbing

수수한개발자 2022. 8. 7.
728x90

Mock 객체의 행동이란

  • 리턴 값이 있는 메소드는 모두 Null 을 리턴하고 있다.
    • Optional 타입인 경우 Optional.empty로 리턴
  • Primitive 타입은 모두 Primitive 값을 따르고 있다.
    • Ex. Boolean인 경우 'false' / Integer 혹은 Long인 경우 0
  • Collection의 경우 모두 비어있는 Collection을 가지고 있다.
  • Void 메소드의 경우 예외를 던지지 않고 아무 일도 발생하지 않는다.

Stubbing이란

  • Mock 객체의 행동을 조작하는 것을 말한다.
  • Mock객체의 when 메소드를 활용하여 Stubbing을 진행해보자.
  • Ex. 리턴값이 있는 when 메소드 활용 1

 

StudyService

public Study createNewStudy(Long memberId, Study study) {
    Optional<Member> member = memberService.findById(memberId);
    study.setOwner(member.orElseThrow(() -> 
    new IllegalArgumentException("Member doesn't exist for id: '" + memberId + "'")));
    return repository.save(study);
}

 

StudyServiceTest

@ExtendWith(MockitoExtension.class)
class StudyServiceTest {


    @Test
    void createStudyService(@Mock MemberService memberService,
                            @Mock StudyRepository studyRepository) {
        StudyService studyService = new StudyService(memberService, studyRepository);
        assertNotNull(studyService);

        Member member = new Member();
        member.setId(1L);
        member.setEmail("jisu@email.com");

        when(memberService.findById(1L)).thenReturn(Optional.of(member));
        
        Study study = new Study(10, "java");
        studyService.createNewStudy(1L, study);
    }

}

Stubbing이 Mock 객체의 행동을 조작한다고 했습니다. 

만약에 아이디가 1인 객체를 리턴해주었으면 좋겠다고 개발자가 Mock객체의 행동을 조작하고 싶을때 어떻게 하는지 알아 보겠습니다.

Member객체를 만듭니다. Member 객체를 만들어 Id에 1과 Email을 넣어줬습니다.

그 후의 when은 ~하면이라고 이해하면 쉽습니다. 아이디가 1인 member가 호출되면~ > thenReturn : 리턴해라

member는 Optional이기떄문에 member를 감싸줍니다.

 

그리고 Study가 호출될때 1L 은 파라미터로 StudyService클래스의 createNewStuidy 메소드의 memberService.findById(memberId)로 전달됩니다.

여기서 memberService는 위에서 만든 Mock 객체입니다.

저희는 when 절에 findById가 1이라는 값으로 호출되면 바로 위에서만든 Member객체가 리턴되도록 Stubbing을 해 놓은 것입니다.

그래서 studyService.createNewStudy에서 파라미터로 1L이 넘어가서 호출될때면 test코드에서 만든 Member객체가 리턴되게 됩니다.

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

        Member member = new Member();
        member.setId(1L);
        member.setEmail("jisu@email.com");

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

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

//        Study study = new Study(10, "java");
//        studyService.createNewStudy(1L, study);

[Mockito] Mock 객체 Stubbing - StudyServiceTest

그래서 위와같이 테스트해도 통과가 되는 모습입니다.

여기서  when(memberService.findById(2L)).thenReturn(Optional.of(member)); 2로 아이디로 넣는다면 테트스가 통과하지 못합니다.

여기서 ArgumentMatchers 라는게 있습니다. 조금더 범용적으로 작성할 수 있습니다.

ArgumentMatchers.any()를 하게 되면 어떤 파라미터를 넘겨주든 같은 객체가 리턴되게 됩니다.

 

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

Member member = new Member();
member.setId(1L);
member.setEmail("jisu@email.com");

when(memberService.findById(any())).thenReturn(Optional.of(member));

assertEquals("jisu@email.com", memberService.findById(1L).get().getEmail());
assertEquals("jisu@email.com", memberService.findById(2L).get().getEmail());

[Mockito] Mock 객체 Stubbing - StudyServiceTest

그래서 테스트가 통과 되게 됩니다.

 

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

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

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

    Member member = new Member();
    member.setId(1L);
    member.setEmail("jisu@email.com");

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

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

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

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

위와 같을떄 첫번째는 Optional로 member객체를 리턴하고 두번째는 예외, 세번째는 비어있는 값을 리턴하게 했습니다.

[Mockito] Mock 객체 Stubbing - StudyServiceTest

테스트가 통과되는 모습입니다.

지금까지 Stubbing 하는 방법을 알아봤습니다.

728x90

'Spring Boot > Mockito' 카테고리의 다른 글

[Mockito] BDD 스타일 API + BDD  (0) 2022.08.07
[Mockito] Verify(검증)  (0) 2022.08.07
[Mockito] Mockito 시작하기  (0) 2022.08.07
[Mockito] Mockito  (0) 2022.08.07

댓글