mock() vs @Mock vs @MockBean 이제 그만 헷갈리자!

2023. 6. 25. 04:27·프로그래밍/Spring

테스트를 수행하다보면, 실제 객체를 대신해주는 테스트용 객체를 생성해 줄 때, mock을 사용하게 됩니다. 이때마다 사용했던 mock() 과 @Mock 그리고 @MockBean 세가지에 대해 정리해보겠습니다.

Mockito.mock()

Mockito.mock() 메서드를 사용하면 클래스 또는 인터페이스의 mock 객체를 생성할 수 있습니다.

또한 mock 객체를 사용해, 해당 객체가 가진 메서드의 반환값을 조작하거나 해당 메서드가 호출되었는지 확인할 수 있습니다.

@Test
public void UserRepository를mocking하고_count메서드가실행되면_모킹한값을리턴한다() {
    UserRepository localMockRepository = Mockito.mock(UserRepository.class);
    Mockito.when(localMockRepository.count()).thenReturn(111L);

    long userCount = localMockRepository.count();

    Assert.assertEquals(111L, userCount);
    Mockito.verify(localMockRepository).count();
}

이렇게 mock() 메서드를 사용하여 mocking된 객체와, 해당 객체의 메서드를 조작해 원하는 값으로 리턴값을 조작할 수 있습니다.

@Mock 애노테이션

@Mock 어노테이션은 앞서 설명한, Mockito.mock() 메서드의 축약어라고 볼 수 있습니다.

  • 이 애노테이션은 Mockito.mock()메서드와 달리 테스트 클래스에서만 사용해야 합니다.
  • 또한 Mockito annotation을 활성화해야만, @Mock 어노테이션을 사용할 수 있습니다.

@Mock 어노테이션을 활성화 하는 방법으로는 두가지가 있습니다.

  • MockitoJunitRunner를 사용해 활성화한다(Junit4에서의 방법)
    • Junit5에서는@ExtendWith(MockitoExtension.class) 메서드로 활성화 할 수 있습니다.
@ExtendWith(MockitoExtension.class)
public class MockAnnotationUnitTest {
    
    @Mock
    UserRepository mockRepository;
    
    @Test
    public void givenCountMethodMocked_WhenCountInvoked_ThenMockValueReturned() {
        Mockito.when(mockRepository.count()).thenReturn(123L);

        long userCount = mockRepository.count();

        Assert.assertEquals(123L, userCount);
        Mockito.verify(mockRepository).count();
    }
}

이렇게 mocking을 하게 되면, 테스트 코드의 가동성을 높일 수 있고, @Mock 을 사용하게 되면, 테스트가 실패 했을 때 실패 메시지에 세부 내용이 표시되므로 디버깅에 용이합니다.

Wanted but not invoked:
mockRepository.count();
-> at org.baeldung.MockAnnotationTest.testMockAnnotation(MockAnnotationTest.java:22)
Actually, there were zero interactions with this mock.

  at org.baeldung.MockAnnotationTest.testMockAnnotation(MockAnnotationTest.java:22)

또한 mocking을 설정할 때, @InjectMocks 를 사용하게 되면, mocking된 객체들을 해당 애노테이션이 설정된 객체에 주입해주기에, mock 객체 주입과 관련된 설정 코드의 양을 줄일 수 있습니다.

  • MockitoAnnotations.initMocks() 메서드를 명시적으로 호출해, 활성화한다

@MockBean 애노테이션

스프링 애플리케이션 컨텍스트에 Mock 객체를 추가하기 위해 @MockBean 을 사용할 수 있습니다.

해당 애노테이션으로 mocking 된 객체는 스프링 애플리케이션 컨텍스트에서 동일한 유형을 가진 기존 빈을 대체합니다.

만약 동일한 유형의 빈이 정의되어 있지 않으면 새로운 Bean이 추가됩니다.

이 애노테이션은 외부 서비스와 같은 특정 빈을 모킹해야 하는 통합 테스트 작성시에 유용합니다.

@MockBean 애노테이션을 사용하려면 SpringRunner를 사용하여 테스트를 실행해야 합니다.(Junit4기준)

  • Junit5에서는 @ExtendWith(SpringExtension.class) 를 사용하면 됩니다
@RunWith(SpringRunner.class)
public class MockBeanAnnotationIntegrationTest {
    
    @MockBean
    UserRepository mockRepository;
    
    @Autowired
    ApplicationContext context;
    
    @Test
    public void givenCountMethodMocked_WhenCountInvoked_ThenMockValueReturned() {
        Mockito.when(mockRepository.count()).thenReturn(123L);

        UserRepository userRepoFromContext = context.getBean(UserRepository.class);
        long userCount = userRepoFromContext.count();

        Assert.assertEquals(123L, userCount);
        Mockito.verify(mockRepository).count();
    }
}

위 코드와 그림처럼 UserRepository 필드에 애노테이션을 사용하게 되면, mocking된 객체가 해당 필드에 주입되고 애플리케이션 컨텍스트에 등록되게 됩니다.

결론

mock() 메서드나, @Mock 를 사용하게 되면, 스프링 애플리케이션 컨텍스트를 로딩하지 않고도 사용 할 수 있기에, 단위 테스트 시에 유용하게 사용 될 수 있을 겁니다. 또한 단위 테스트 시에도 무분별하게 mocking을 통해 테스트를 작성하기 보다는 위 글에서 설명하는 것 처럼 외부 라이브러리와 같이직접 제어를 할 수 없는 경우에 mocking을 사용하면 좋을 것 입니다.

반면 @MockBean 메서드는 스프링 애플리케이션 컨텍스트를 로딩해야 사용할 수 있기 때문에, 스프링 애플리케이션 컨텍스트를 필요로 하는 통합 테스트에서 mocking이 필요할 때 유용하게 사용될 수 있을 것 입니다.

이렇듯 각 애노테이션이나 메서드의 특징에 대해 알고 사용해야 올바르게 사용할 수 있는 가장 빠른 길이라고 생각해 글을 작성하게 됐습니다.

'프로그래밍 > Spring' 카테고리의 다른 글

Spring Data Common 모듈 에서의 디자인 패턴  (2) 2023.05.27
Micro Service에서 WebFlux의 장점  (0) 2022.12.28
Spring WebMVC VS WebFlux  (0) 2022.12.28
'프로그래밍/Spring' 카테고리의 다른 글
  • Spring Data Common 모듈 에서의 디자인 패턴
  • Micro Service에서 WebFlux의 장점
  • Spring WebMVC VS WebFlux
황심지
황심지
  • 황심지
    꾸준함이 진리다
    황심지
  • 전체
    오늘
    어제
    • 분류 전체보기 (51)
      • 프로그래밍 (12)
        • 운영체제 (0)
        • Spring (4)
        • Java (10)
        • SQL (0)
        • HTTP (2)
        • 회고 (2)
        • Network (0)
        • 프로젝트 (12)
        • Infra (2)
        • 데이터베이스 (3)
        • TIL (1)
        • 파이썬 (2)
      • 운동 (0)
        • 거인화 루틴 일지 (0)
        • 과부하 훈련 일지 (0)
        • 운동 관련 이모저모 (0)
  • 블로그 메뉴

    • 홈
    • 방명록
    • 글쓰기
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    직장인자기계발
    직장인인강
    python
    세션
    에프랩 후기 자바 백엔드
    개인회고록
    1년회고록
    페이징 최적화
    쿼리 성능
    2023년회고
    django orm
    spring
    개인성장
    에프랩 후기
    CAP Theorem
    패캠챌린지
    패스트캠퍼스
    그런 RESTAPI로 괜찮은가?
    대용량 트래픽
    Java
    webflux
    chatops
    배포 방식
    패스트캠퍼스후기
    한번에끝내는코딩테스트369Java편초격차패키지Online
    에프랩 후기 자바 백엔드 부트캠프
    레디스 세션
    position argument
    CAP 이론
    F-Lab 후기
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
황심지
mock() vs @Mock vs @MockBean 이제 그만 헷갈리자!
상단으로

티스토리툴바