[Java] Mockito
Mockito?
Mockito는 실제 객체를 모방한 Mock 객체를 쉽게 생성하여 단위 테스트를 진행할 수 있는 오픈소스 프레임워크이다.
아마 프로젝트에서 테스트 코드를 짜본 경험이 있다면 Mockito를 한 번쯤 써봤을 것이다.
Mock 프레임워크는 Mockito이외에도 EasyMock, JMock 등이 있다.
그럼 Mockito를 왜 사용하는 걸까?
먼저 다음 예시 코드를 보며 알아보자.
@Service
public class PostService {
private PostRepository postRepository;
public PostService(PostRepository postRepository) {
this.postRepository = postRepository;
}
public Post findById(Long id) {
return postRepository.findById(id).orElseThrow(EntityNotFoundException::new);
}
}
위 코드를 테스트 한다면 어떻게 작성해야 할까?
@SpringBootTest
public class PostServiceTest {
@Autowired PostService postService;
@Autowired PostRepository postRepository;
Post post;
@BeforeEach
void init() {
post = new Post();
postRepository.save(post);
}
@Test
@DisplayName("게시글 id를 통해 게시글을 조회할 수 있다.")
void findByIdTest() {
Post findPost = postService.findById(1L);
assertThat(findPost.getId()).isEqualTo(1L);
}
}
위와 같이 SpringBoot 실행 후 스프링 빈을 통해 의존성을 다 주입받고 객체를 저장하여 테스트를 실시해야한다.
뭔가 PostService만을 위한 단위 테스트라기엔 postRepository도 받아오고 외부 db도 사용하고,, 너무 무거워보인다.
때문에 우리는 PostService를 위한 단위 테스트인데 굳이 그럴 필요가 있을까 생각해보아야 한다.
여기서 활용할 수 있는 것이 바로 mock이다.
mock?
mock이란 주로 객체 지향 프로그래밍으로 개발한 프로그램을 테스트 할 경우 테스트를 수행할 모듈과 연결되는 외부의 다른 서비스나 모듈들을 실제 사용하는 모듈을 사용하지 않고 실제의 모듈을 "흉내"내는 "가짜" 모듈을 작성하여 테스트의 효용성을 높이는데 사용하는 객체이다. - 위키백과
테스트 대역을 테스트 더블(Test Doubles)이라고 부른다. 테스트 더블에는 다음과 같은 종류가 있다.
- Dummy
- Mock
- Spy
- Stub
- Fake
그 중 많이 알려져있고, spring starter에 포함되어 있는 mockito를 사용해보자.
아까 위에서 작성했던 테스트 코드를 Mockito를 사용하여 Repository를 테스트를 위한 모의 객체로 만들고 PostService를 테스트 해 볼 것이다. (JUnit 5를 기반으로 작성하였다)
@ExtendWith(MockitoExtension.class) // (1)
public class PostServiceTest {
Post post;
@Mock PostRepository postRepository; // (2)
@InjectMocks PostService postService; // (3)
@Test
@DisplayName("게시글 id를 통해 게시글을 조회할 수 있다.")
void findByIdTest() {
Post post = new Post();
given(postRepository.findById(any(Long.class))).willReturn(post); // (4)
Post findPost = postService.findById(1L);
assertThat(findPost).isEqualTo(post);
}
}
(1) @ExtendWith를 통해 확장을 선언적으로 등록해 줄 수 있다. 여기선 Mockito를 사용하기 위한 MockitoExtension을 등록하였다.
(2) PostRepository를 Mock 객체로 만들어준다.
(3) @InjectMocks를 선언하여 만든 Mock 객체들이 PostService에 주입될 수 있게 한다.
(4) given() 구문을 통해 Mock 객체가 어떤 값을 반환시키도록 할지 정할 수 있다.
이렇게 해서 PostService를 위한 단위 테스트를 수행할 수 있다.
또 단위 테스트 수행 시 메서드 단위로 수행하기 보단 행동(시나리오) 단위로 수행할 것을 권장하는데, 이때 BDD의 개념을 가져와 테스트를 작성해 볼 수 있다.
BDD는 TDD를 근간으로 파생된 개발 방법으로, 행위 주도 개발(Behaviour Driven Development)이라고 부른다.
@ExtendWith(MockitoExtension.class)
public class PostServiceTest {
Post post;
@Mock PostRepository postRepository;
@InjectMocks PostService postService;
@Test
@DisplayName("게시글 id를 통해 게시글을 조회할 수 있다.")
void findByIdTest() {
// given
Post post = new Post();
given(postRepository.findById(any(Long.class))).willReturn(post);
// when
Post findPost = postService.findById(1L);
// then
assertThat(findPost).isEqualTo(post);
}
}
이렇게 given, when, then으로 나누어 시나리오 기반으로 테스트 케이스를 작성하고 테스트를 수행할 수 있다.
이렇게 하면 각 행위별로 테스트를 수행할 수 있으며, 객체의 행위가 중요한 객체지향 개발 방식을 테스트하는 좋은 방법이 될 수 있다.
마무리
Mockito는 안 쓸수록 좋은 프레임워크라는 말이 있다.
물론 Mockito를 사용하여 테스트를 작성하는 것은 외부 프레임워크에 의존하여 테스트를 작성하는 것이다.
때문에 만약 Mockito를 없애고 다른 테스트 프레임워크를 사용해야하는 상황이 발생한다면, 많은 의존성으로 인해 곤욕을 치를 수도 있을 것이다.
때문에 Mockito를 사용하지 않고 직접 mock 객체를 만들어 테스트 코드를 작성해볼 수 있으니, 한 번 연습해보는 것을 추천한다.
'Language > Java' 카테고리의 다른 글
[Java] utility class는 무엇으로 구현하는 것이 좋을까? (1) | 2024.04.15 |
---|---|
[Java] 제네릭(Generic) (0) | 2024.03.12 |
[Java] hashCode() (1) | 2023.07.02 |
[Java] Java 버전 별 특징 (2) | 2023.04.14 |
[Java] Java 11 특징 (0) | 2023.04.13 |
댓글
이 글 공유하기
다른 글
-
[Java] utility class는 무엇으로 구현하는 것이 좋을까?
[Java] utility class는 무엇으로 구현하는 것이 좋을까?
2024.04.15 -
[Java] 제네릭(Generic)
[Java] 제네릭(Generic)
2024.03.12 -
[Java] hashCode()
[Java] hashCode()
2023.07.02 -
[Java] Java 버전 별 특징
[Java] Java 버전 별 특징
2023.04.14