Mockito 객체
이번에는 Mockito 객체에 대해서 알아보도록 하겠습니다.
이 글은 백기선님 더 자바, 애플리케이션을 테스트하는 다양한 방법을 정리한 글입니다.
더 자바, 애플리케이션을 테스트하는 다양한 방법 - 인프런 | 강의
자바 프로그래밍 언어를 사용하고 있거나 공부하고 있는 학생 또는 개발자라면 반드시 알아야 하는 애플리케이션을 테스트하는 다양한 방법을 학습합니다., 그냥 개발자를 넘어 '더 나은 개발
www.inflearn.com
Mock 객체를 사용해서 테스트를 해야 할 때
코드 작성하는 클래스의 기능들이 의존하는 인터페이스의 구현체는 없고 그 인터페이스를 이용해서 작성해야 하는 코드의 경우
해당 코드가 제대로 작성되고 있는 코드인지 알려면 Mocking을 해야 합니다.
구현체가 있는 경우 선택할 수 있지만 없는 경우에는 Mocking을 해서 테스트를 진행해야 합니다.
Mock 객체 생성
Mock 객체를 생성하는 방법은 크게 3가지가 있습니다.
@ExtendWith(MockitoExtension.class)
public class MockObjectTest {
@Mock
MemberService memberService;
@Mock
StudyRepository studyRepository;
@Test
@DisplayName("인스턴스를 통해 생성")
void createInstanceStudyTest(){
MemberService instanceMember = mock(MemberService.class);
StudyRepository instanceStudy = mock(StudyRepository.class);
StudyService studyService = new StudyService(instanceMember, instanceStudy);
}
@Test
@DisplayName("애노테이션을 통해 생성")
void createAnnotationTest(){
StudyService studyService = new StudyService(memberService, studyRepository);
}
@Test
@DisplayName("생성자를 사용해서 생성")
void createConstructorTest(@Mock MemberService memberService, @Mock StudyRepository studyRepository){
StudyService studyService = new StudyService(memberService, studyRepository);
}
}
위 코드에서 보시다시피 인스턴스를 통해 생성, 애노테이션을 이용해서 생성, 생성자를 이용해서 생성하는 방법 총 3가지가 있습니다.
인스턴스를 이용해서 생성하는 방법
Mockito.mock(클래스 타입)으로 인스턴스를 생성하게 됩니다.
애노테이션을 통해 생성하는 방법
객체에 @Mock을 붙이고 클래스에 @ExtendWith(MockitoExtension.class) 확장 모듈을 추가하여 사용가능합니다.
생성자를 사용해서 생성하는 방법
인자에 @Mock 애노테이션을 붙여 사용가능합니다. 이 또한 @ExtendWith(MockitoExtension.class) 확장 모듈을 추가해야 합니다.
Mock 객체 Stubbing
Mock 객체의 행동을 조작하는 것을 Stubbing이라고 합니다.
(기본적으로 Stubbing 하지 않은 Mock객체에는 Null, Primitive 타입의 값은 Primitive 타입 기본 값, 컬렉션은 비어있는 컬렉션, void 메서드는 아무것도 하지 않습니다.)
Stubbing 하는 방법
@Test
@DisplayName("생성자를 사용해서 생성")
void createStubbingTest(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
Member member = new Member();
member.setEmail("kibong@email.com");
member.setId(1L);
when(memberService.findById(1L)).thenReturn(Optional.of(member));
assertEquals("kibong@email.com", memberService.findById(1L).get().getEmail());
assertEquals("kibong@email.com", memberService.findById(1L).get().getEmail());
StudyService studyService = new StudyService(memberService, studyRepository);
}
stubbing 하는 방법은 Mockito.when()을 이용해서 stubbing 하면 됩니다.
Mockito.when은 언제 호출하느냐 그리고. thenReturn() 그리고 무엇을 리턴하느냐가 필요합니다.
그래서 when(memberService.findById(1L)).thenReturn(Optional.of(member)); memberService.findById를 호출하면 Optional.of(member)을 리턴하겠다는 말이 됩니다.
예외 테스트
@Test
@DisplayName("stubbing 예외 테스트")
void stubbingThrowTest(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
when(memberService.findById(1L)).thenThrow(new RuntimeException());
memberService.findById(1L);
doThrow(new IllegalArgumentException()).when(memberService).validate(1L);
memberService.validate(1L);
}
thenReturn 대신 thenThrow을 사용해서 리턴 대신 예외를 발생시킬 수도 있습니다
doThrow도 마찬가지로 예외를 넘겨주고 when 통해 어느 호출 때 예외가 발생할 수 있도록 테스트도 가능합니다.
여러 리턴 테스트
@Test
@DisplayName("stubbing 여러 리턴 테스트")
void stubbingBuilderTest(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
Member member = new Member();
member.setEmail("kibong@email.com");
member.setId(1L);
when(memberService.findById(1L))
.thenReturn(Optional.of(member))
.thenThrow(new IllegalArgumentException())
.thenReturn(Optional.empty());
assertEquals("kibong@email.com", memberService.findById(1L).get().getEmail());
assertThrows(IllegalArgumentException.class, () -> {
memberService.findById(1L);
});
assertTrue(memberService.findById(1L).isEmpty());
}
하나의 when 여러 개 결과를 달아주면 되는데 when에 여러 개의 빌더를 달아 테스트할 수 있음을 알 수 있습니다.
위 코드처럼. thenReturn. thenThrow. thenReturn를 통해 처음에는 Optional <Member> 리턴을 두 번째에는 예외를 세 번째에는 empty를 리턴하게 됩니다.
Mockito 객체 확인
Mockito 객체가 어떤 일이 벌어졌었는지 확인이 가능합니다.
@ExtendWith(MockitoExtension.class)
public class MockObjectCheckTest {
@Test
@DisplayName("Mock 객체 체크 테스트")
void objectCheckTest(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
Study study = new Study(10, "테스트");
Member member = new Member();
member.setEmail("kibong@email.com");
member.setId(1L);
when(memberService.findById(1L)).thenReturn(Optional.of(member));
when(studyRepository.save(study)).thenReturn(study);
Optional<Member> byId = memberService.findById(1L);
StudyService studyService = new StudyService(memberService, studyRepository);
Study newStudy = studyService.createNewStudy(byId.get().getId(), study);
assertEquals(newStudy.getOwnerId(), member.getId());
//Mock 객체를 얼마나 사용하고 있는지 확인 가능
verify(memberService, times(1)).notify(study);
verify(memberService, never()).validate(any());
verifyNoMoreInteractions(memberService);
}
}
verify를 통해서 Mock객체를 얼마나 사용하고 있는지 테스트가 가능합니다.
작성한 코드의 verify()를 보시면 memberService가 notify를 study라는 매개변수를 가지고 1번 실행했는지에 대한 테스트입니다.
verifyNoMoreInteractions를 통해 호출을 더 했는지에 대한 테스트도 해볼 수 있습니다.
Mockito BDD API
BDD(Behavior Driven Development) 사용자의 행위나 시스템의 동작을 중심으로 개발 즉, 애플리케이션이 어떻게 "행동" 해야 하는지에 대한 구성 방법입니다.
BDD는 Given-When-Then의 문법으로 BDD를 구성할 수 있습니다.
Mockito에서는 BDD API를 지원하고 있어 사용해 보도록 하겠습니다.
@ExtendWith(MockitoExtension.class)
public class MockBDDAPITest {
@Test
@DisplayName("BDD API 테스트")
void bddApiTest(@Mock MemberService memberService, @Mock StudyRepository studyRepository){
//Given
Study study = new Study(10, "테스트");
Member member = new Member();
member.setEmail("kibong@email.com");
member.setId(1L);
given(memberService.findById(1L)).willReturn(Optional.of(member));
given(studyRepository.save(study)).willReturn(study);
Optional<Member> byId = memberService.findById(1L);
StudyService studyService = new StudyService(memberService, studyRepository);
//When
Study newStudy = studyService.createNewStudy(byId.get().getId(), study);
//Then
assertEquals(newStudy.getOwnerId(), member.getId());
then(memberService).should(times(1)).notify(study);
then(memberService).shouldHaveNoMoreInteractions();
}
}
- given : 객체 생성 및 이전에 사용했던 when부분이 given에 해당됩니다.
- when : studyService.createNewStudy를 테스트하는 것이므로 when에 해당됩니다.
- then : verify 했는 부분이 then에 해당됩니다.
이제 코드르 자세히 살펴보면 이제는 when대신에 given을 사용하는 것을 볼 수 있습니다.
given은 when과 비슷하게 동작합니다. given(호출되어야 하는 동작). willReturn(리턴 값);
when과 같이 호출되어야 하는 동작일 때 리턴 값을 리턴합니다.
then은 verify와 비슷한데 then(객체).should(times(횟수))). 동작(매개변수);
verify와 같이 객체의 동작이 매개변수를 가지고 몇 번 동작했는지 검증할 수 있습니다.
오늘은 Mock 객체 생성, Stubbing, 객체 확인, Mock BDD API에 대해서 알아보았습니다.
다음에는 TestContainer로 찾아뵈도록 하겠습니다. 감사합니다.
GitHub - kibongcoders/junit5
Contribute to kibongcoders/junit5 development by creating an account on GitHub.
github.com
더 자바, 애플리케이션을 테스트하는 다양한 방법 - 인프런 | 강의
자바 프로그래밍 언어를 사용하고 있거나 공부하고 있는 학생 또는 개발자라면 반드시 알아야 하는 애플리케이션을 테스트하는 다양한 방법을 학습합니다., 그냥 개발자를 넘어 '더 나은 개발
www.inflearn.com