본문 바로가기
Back-end/Spring Boot

[SpringTest] @MockBean과 @Mock 차이

by whatamigonnabe 2022. 12. 1.

들어가며

테스트를 작성하며 MockBean과 Mock을 둘 다 사용하게 되어, 간략하게 정리해볼까합니다.

 

SpringBean이 필요하면 @MockBean, 아니면  @Mock을 사용하자

가장 중요한 것은 바로 이거라고 생각합니다.

테스트해야할 클래스가 Spring으로 부터 빈을 주입받아야하는 상황이라면 -> @MockBean을

그렇지 않다면 -> @Mock을 사용하는 것입니다.

 

@MockBean이 붙은 필드의 클래스는 SpringBoot 실행 시 Bean을 구성할 때, 가짜 객체로 Bean을 만들어 DI 해줍니다.

@Mock은 SpringBoot를 실행하지 않고 @Mock이 붙은 필드의 클래스를 가짜 개체로 만들어 직접 사용해야합니다. 

 

대체로 단위테스트는 가장 작은 단위로 의존성을 제거하고 보는 것이 좋기 때문에, 왠만하면 @Mock을 사용하는 것이 좋을 것이라는 생각이 듭니다. 또, Spring을 실행하지 않아도 되기 때문에 훨씬 속도가 빠르기도 합니다.

 

어떻게 사용하는가?

@MockBean

스프링부트를 사용하기 때문에 @SpringBootTest를 붙여준후, 

테스트하고자하는 클래스에 @Autowired를 붙이고, 이 클래스가 의존하고 있는 클래스에 @MockBean을 붙입니다.

@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class ChatRoomServiceTest {
    @MockBean
    private ChatRoomRepository chatRoomRepository;
    @Autowired
    private ChatRoomService chatRoomService;
    ...
}

@Mock

@ExtendWith를 붙여준 후(이것 이외에도 여러 방법이 있습니다.), 테스트하고 싶은 클래스에 @InjectMocks를, 의존 클래스에 @Mock을 작성해줍니다.

@ExtendWith(MockitoExtension.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class ChatServiceTest {
    @Mock
    private ChatMessageRepository chatMessageRepository;
    @Mock
    private UserUtilsForWebSocket userUtilsForWebSocket;
    @InjectMocks
    private ChatService chatService;
	...
}

 

 

그리고 Mock개체의 기능이 사용되는 곳을 테스트할 경우 아래와 같이 작성합니다.

given(userInChatRoomRepository.contain(eq(roomId1Key), any(String.class)))
        .willReturn(true);

 

given의 첫 번째 인자가 실행될 때 실제 내부 로직을 수행하지 않고, .willReturn에 지정한 값을 반환합니다.

또한 특정한 값에 특정한 리턴값을 매칭해주고 싶다면 eq(Object)를, 무엇이등 상관 없다면 any(Object)메서드로 목객체를 조작할 수 있습니다.

 

나가며

아직 배워야할 것이 많고, 테스트 방법도 엄청 다양한 것 같습니다. 사실 TDD처럼 바로바로 테스트를 짜는 것과 나중에 한번에 테스트를 짜는 것을 둘 다 경험했었는데, 저는 TDD가 더 재밌다고 생각했습니다. 이미 개발 완료된 것을 테스트하는 것이 졸립고 지루한 감이 있었습니다. 반면 TDD로 작성하면 더 재미있게 할 수 있었습니다. 다음부턴, 바로바로 테스트 작성하자!