Mockito 사용하기2

34026 단어 MockitoJUnit5JUnit5

1. Mock 객체 확인

1-1. 특정 메서드 동작 및 호출 횟수 확인

  • Mockito의 verify() 메서드를 통해 특정 메서드가 몇번 실행됬는지 확인할 수 있다.
public class StudyService {

		public Study createNewStudy(Long memberId, Study study) {
        Optional<Member> member = memberService.findById(memberId);
        study.setOwnerId(memberId);

        Study newStudy = repository.save(study);
        //memberService.notify(newStudy);
        return repository.save(study);
    }

		...
}
@ExtendWith(MockitoExtension.class)
class StudyServiceTest {

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

        Member member = new Member();
        member.setId(1L);
        member.setEmail("[email protected]");

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

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

        studyService.createNewStudy(1L, study);

        assertNotNull(study.getOwnerId());
        assertEquals(member.getId(), study.getOwnerId());

        Mockito.verify(memberService, Mockito.times(1)).notify(study); // notify 메서드가 한번 호출하기를 기대
        Mockito.verify(memberService, Mockito.never()).validate(Mockito.any()); // validate 메서드는 호출되지 않길 기대
    }
}

  • 테스트코드에 맨 마지막줄을 보면 memberService의 notify() 메서드가 1번 호출되기를 기대했지만 주석처리 해놓았기 때문에 notify()메서드는 동작하지 않았고 에러가 난다.

  • 또한 never() 메서드를 이용해 메서드가 호출되지 않았는지 확인할 수 있다.

1-2. 호출 순서 확인

public class StudyService {
    private final MemberService memberService;
    private final StudyRepository repository;

    ...

    public Study createNewStudy(Long memberId, Study study) {
        Optional<Member> member = memberService.findById(memberId);
        study.setOwnerId(memberId);

        Study newStudy = repository.save(study);
        memberService.notify(newStudy);
        memberService.notify(member.get());
        return repository.save(study);
    }
}
  • 새 스터디를 만들었다는 notify() 메서드 호출 후, 회원에게 알리는 notify() 메서드를 호출
@ExtendWith(MockitoExtension.class)
class StudyServiceTest {
		@Test
    void stubbing(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
        ...

        InOrder inOrder = Mockito.inOrder(memberService);

	//성공
        inOrder.verify(memberService).notify(study);
        inOrder.verify(memberService).notify(member);

	//실패
	inOrder.verify(memberService).notify(member);
        inOrder.verify(memberService).notify(study);
    }

}
  • Inorder를 먼저 생성해 준 후
    실제로 호출되는 메서드 순서대로 verify()를 하면 테스트는 성공한다.

1-3. 특정 시점에 아무일도 일어나지 않았는지 확인

  • 즉 특정 메서드를 호출한 후에 아무 메서드도 호출되지 않았는지 확인할 수 있다.
public class StudyService {
    private final MemberService memberService;
    private final StudyRepository repository;

		...

    public Study createNewStudy(Long memberId, Study study) {
        Optional<Member> member = memberService.findById(memberId);
        study.setOwnerId(memberId);

        Study newStudy = repository.save(study);
        memberService.notify(newStudy);
        memberService.notify(member.get());
        return repository.save(study);
    }
}
@ExtendWith(MockitoExtension.class)
class StudyServiceTest {
		@Test
    void stubbing(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
        ...

	//실패
        Mockito.verify(memberService, Mockito.times(1)).notify(study); // notify 메서드가 한번 호출하기를 기대
	Mockito.verifyNoMoreInteractions(memberService); // 실패 아래 notify()메서드가 동작하므로
        Mockito.verify(memberService, Mockito.times(1)).notify(member); // notify 메서드가 한번 호출하기를 기대
        
	//성공
	Mockito.verify(memberService, Mockito.times(1)).notify(study); // notify 메서드가 한번 호출하기를 기대
        Mockito.verify(memberService, Mockito.times(1)).notify(member); // notify 메서드가 한번 호출하기를 기대
	Mockito.verifyNoMoreInteractions(memberService);
    }

}
  • verifyNoMoreInteractions() 메서드를 이용하면 된다.

2. Mockito BDD 스타일 API

2-1. BDD

  • BDD란?
    • Behaviour Driven Development로 행위 주도 개발이라고 한다. 애플리케이션이 어떻게 행동해야 하는지에 대한 공통된 이해를 구성하는 방법으로 TDD에서 창안되었다.
  • 행동에 대한 스펙
    • Narrative (행동에대한 설명을 정의할 때)
      • As a / i want / so that
    • Acceptance criteria
      • Given / When / Then
      • 어떤 상황이 주어졌을 때 / 어떤 행동을 했을 때 / 이런 결과가 나와야 한다.

2-2. BDD스타일 API 적용

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

        Member member = new Member();
        member.setId(1L);
        member.setEmail("[email protected]");

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

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

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

        //then
        Mockito.verify(memberService, Mockito.times(1)).notify(study); // notify 메서드가 한번 호출하기를 기대
        Mockito.verify(memberService, Mockito.times(1)).notify(member); // notify 메서드가 한번 호출하기를 기대
        Mockito.verify(memberService, Mockito.never()).validate(Mockito.any()); // validate 메서드는 호출되지 않길 기대

        Mockito.verifyNoMoreInteractions(memberService);
    }
}
  • 이처럼 Given, When, Then으로 나눌 수 있다.

  • 이를 위한 라이브러리 JBehave같은 것들도 지원하는데 굳이 사용할필요까진 없고
    Mockito에서도 BDD를 위해 지원하는 기능들이 있다.

  • 예로 위에서 보면 Mockito.when() 을 사용하는 부분은 Given에 해당하지만 API가 when이라서
    조금 어울리지 않는다. 따라서 when() 대신 given()이라는 API를, verify() 대신 then() 등을 제공하고 있다.


Ref

좋은 웹페이지 즐겨찾기