워밍업 클럽 2기 BE 클린코드&테스트 : 미션 - Day 18

워밍업 클럽 2기 BE 클린코드&테스트 : 미션 - Day 18

워밍업 클럽 2기 BE 클린코드&테스트 : 미션 - Day 18

 

 이 글은 박우빈님의 강의를 참조하여 작성한 글입니다.

 

미션 - Day 18

 

미션 내용

1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다.

 

2. 아래 3개의 테스트가 있습니다. 내용을 살펴보고, 각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치하고 싶으신가요? (@BeforeEach에 올라간 내용은 공통 항목으로 합칠 수 있습니다. ex. 1-1과 2-1을 하나로 합쳐서 @BeforeEach에 배치)

 

게시판 게시물에 달리는 댓글을 담당하는 Service Test
댓글을 달기 위해서는 게시물과 사용자가 필요하다.
게시물을 올리기 위해서는 사용자가 필요하다.

 


미션1

테스트를 통해 검증하는 과정에서 여러 객체(모듈)이 상호 작용하고 객체 간 의존성이 클수록 필요한 데이터를 준비하는데만 오랜 시간을 걸린다. 배보다 배꼽이 큰 경우를 막기 위해 검증하지 않는 객체(모듈)은 Mock 처리하여 검증하고자 하는 것에만 더 집중할 수 있다. 우리는 아래와 같은 어노테이션을 통해 이러한 이점을 얻을 수 있다.

 

@Mock : 실제 객체 대신에 가짜(Mock) 객체를 생성한다.

@MockBean : Spring 테스트 환경에서 스프링 컨텍스트에 등록된 Bean을 Mock 객체로 대체한다.

@Spy : 실제 객체를 생성하되, 특정 메서드에 대해 행위와 결과를 지정할 수 있다.

@SpyBean : Spring 테스트 환경에서 스프링 컨텍스트에 등록된 Bean을 Spy 객체로 대체한다.

@InjectMocks : 의존성 주입을 자동으로 수행한다. 테스트 대상 클래스의 인스턴스를 생성하고, 해당 클래스가 의존하는 객체들을 @Mock 또는 @Spy로 주입합니다.

 

Bean의 유무 차이(@Mock, @MockBean / @Spy, @SpyBean)

기능에 대한 차이는 없다. 다만 스프링 컨텍스트를 사용한다면 싱글톤 방식으로 각 인스턴스가 관리된다. 대게 단위 테스트 환경에서는 의존성 주입을 위해 @Mock, @Spy를 사용하고 스프링 환경에서 테스트하고 싶을 때는 @MockBean, @SpyBean을 사용하면 된다.

 

  • @injectMocks vs @Autowired

여기서도 Mock, Spy를 통해 의존성을 주입할 때는 @injectMocks을 사용하면 된다.

@Mock 
UserRepository userRepository; 
@InjectMocks 
UserService userService; // userRepository가 주입됨

스프링 컨테이너에서 빈을 가져올 때는 다음과 같이 사용하면 된다.

@MockBean 
UserRepository userRepository; 
@Autowired 
UserService userService; // userRepository가 주입됨

 


미션2

게시판 게시물에 달리는 댓글을 담당하는 Service Test
댓글을 달기 위해서는 게시물과 사용자가 필요하다.
게시물을 올리기 위해서는 사용자가 필요하다.

 


@BeforeEach 
void setUp() {
    사용자 생성에 필요한 내용 준비
    사용자 생성
    게시물 생성에 필요한 내용 준비
    게시물 생성
} 

@DisplayName("사용자가 댓글을 작성할 수 있다.")
@Test
void writeComment() {
    // given
    1-5. 댓글 생성에 필요한 내용 준비

    // when
    1-6. 댓글 생성

    // then
    검증
}

@DisplayName("사용자가 댓글을 수정할 수 있다.")
@Test
void updateComment() {
    // given
    2-5. 댓글 생성에 필요한 내용 준비
    2-6. 댓글 생성

    // when
    2-7. 댓글 수정

    // then
    검증
}

@DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.")
@Test
void cannotUpdateCommentWhenUserIsNotWriter() {
    // given
    3-7. 사용자1의 댓글 생성에 필요한 내용 준비
    3-8. 사용자1의 댓글 생성
    3-3. 사용자2 생성에 필요한 내용 준비
    3-4. 사용자2 생성

    // when
    3-9. 사용자2가 사용자1의 댓글 수정 시도

    // then
    검증        
}

[작성 이유]

@BeforeEach 구조 이유

해당 테스트에 핵심 도메인은 댓글이다. 댓글을 달기 위한 사용자와 게시물을 부수적인 요소이며 댓글을 생성하기 위해서는 사용자와 사용자가 생성한 게시물이 필수라는 조건이 있다. 해당 도메인 로직이 변경되더라도 이는 전제 조건이므로 setUp 메서드에서 구현해도 의미를 담기 충분하다고 판단했고 덤으로 중복도 방지할 수 있다고 생각한다.

 

테스트 별 given, when 절 구조 이유

각 테스트 별 when 절에는 하나의 행위만 있다. 테스트는 하나의 행위에 대한 검증을 해야 한다. 만약 테스트에 2개 이상의 행위를 검증하게 되는 경우 검증하고자 하는 것이 모호해지고 실제로 테스트에 성공하더라도 2개 이상의 행위가 복합적으로 동작했기에 정확한 결과를 예측하기 힘들다.

 

 

댓글을 작성해보세요.

채널톡 아이콘