포스트

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 라이센스를 따릅니다.