Spring Boot Test - Mockito로 mock 만들어 테스트 검증하기
Spring Boot 3에는 Mockito가 포함 되어 있기 때문에 의존성을 별도로 추가하지 않는다.
(Spring Boot 1.4부터 Mockito가 포함 됨 - 관련 내용 )
Mock 만들기
MockitoExtension
을 확장하여 Mockito 어노테이션을 활용하는 방법에 대해 정리
예를 들어,
테스트 할 AaService 객체가 AbService와 AbRepository를 이용하는 로직을 갖고 있다면
AbService와 AbRepository는 @Mock
어노테이션을 사용하여 목 객체로 만들고
AaService는 목 객체를 주입 받아 실행되어야 하므로 @InjectMock
어노테이션을 이용해 선언한다.
@Mock
: 가짜 객체 생성@InjectMock
: 다른 가짜 객체(@Mock)을 주입 받아 사용하는 형태를 띄는 가짜 객체 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@ExtendWith(MockitoExtension.class)
class AaServiceTest {
@Mock AbService abService;
@Mock AbResporitory abRepository;
@InjectMock AaService aaService;
@Test
void test() {
UserEntity userEntity = UserEntity.builder()
.id(50L)
.name("김유저")
.build()
when(abservice.searchUser(50L)).thenThrow(UsernameNotFoundException.class);
when(abRepository.findById(50L)).thenReturn(Optional.empty());
assertThrows(
UsernameNotFoundException.class,
() -> aaService.login(50L)
);
}
}
이 코드에서 when().thenThrow() 와 같은 코드를 stubbing이라고 한다.
mock 객체의 행위에 대한 결과를 설정하는 행위를 의미한다!
Mock 객체 동작 검증 (Verify)
verify()
메서드를 이용하면 실행 메서드 내부에서 특정 기능이 몇 번 실행되었는지 확인하는 검증을 수행할 수 있다.
1
2
3
4
5
6
7
8
9
verify(abService, times(1)).searchUser(id); // 1번 호출되면 성공
verify(abService, never()).update(userEntity); // 호출되지 않으면 성공
// 실행 순서 검증
InOrder in = inOrder(aaService);
in.verify(abService).searchUser(id); // 아래 것 보다 먼저 실행되야 성공
in.verify(abRepository).findById(id); // 위에 것 보다 늦게 실행되야 성공
verifyNoMoreInteractions(abService); // 이 시점 이후 더 이상의 실행이 일어나지 않아야 성공
BDD 스타일
Mockito에서 제공하는 BDDMockito의 메서드를 사용한다.
TDD 스타일에서 사용하던 when()
은 given()
으로, verify()
는 then()
으로 변경하면 된다.
BDD 스타일로 리팩토링
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// when(abservice.searchUser(50L)).thenThrow(UsernameNotFoundException.class);
given(abservice.searchUser(50L)).willThrow(UsernameNotFoundException.class);
// when(abRepository.findById(50L)).thenReturn(Optional.empty());
given(abRepository.findById(50L)).willReturn(Optional.empty());
assertThrows(
UsernameNotFoundException.class,
() -> aaService.login(50L)
);
// verify(abService, times(1)).searchUser(id);
then(abService).should(times(1)).searchUser(id);
// verify(abService, never()).update(userEntity);
then(abService).should(never()).update(userEntity);
// 실행 순서 검증
InOrder in = inOrder(aaService);
in.verify(abService).searchUser(id);
in.verify(abRepository).findById(id);
// verifyNoMoreInteractions(abService);
then(abService).shouldHaveNoMoreInteractions();
참고한 사이트
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.