인프런 워밍업 클럽 3기 BE 클린코드 & 테스트

[인프런 워밍업 클럽 BE 3기 클린코드 & 테스트] Day18 미션

taey 2025. 3. 28. 23:02

Day18 미션

1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다.
2. 아래 3개의 테스트가 있습니다. 내용을 살펴보고, 각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치하고 싶으신가요?(@BeforeEach에 올라간 내용은 공통 항목으로 합칠 수 있습니다. ex. 1-1과 2-1을 하나로 합쳐서 @BeforeEach에 배치)
"@BeforeEach 
void setUp() {
    ❓
} 

@DisplayName(""사용자가 댓글을 작성할 수 있다."")
@Test
void writeComment() {
    1-1. 사용자 생성에 필요한 내용 준비
    1-2. 사용자 생성
    1-3. 게시물 생성에 필요한 내용 준비
    1-4. 게시물 생성
    1-5. 댓글 생성에 필요한 내용 준비
    1-6. 댓글 생성

    // given
    ❓

    // when
    ❓

    // then
    검증
}

@DisplayName(""사용자가 댓글을 수정할 수 있다."")
@Test
void updateComment() {
    2-1. 사용자 생성에 필요한 내용 준비
    2-2. 사용자 생성
    2-3. 게시물 생성에 필요한 내용 준비
    2-4. 게시물 생성
    2-5. 댓글 생성에 필요한 내용 준비
    2-6. 댓글 생성
    2-7. 댓글 수정

    // given
    ❓

    // when
    ❓

    // then
    검증
}

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

    // given
    ❓

    // when
    ❓

    // then
    검증        
}"

 


1)  @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이 정리

  • @Mock vs @MockBean
    • Mock은 단위 테스트, MockBean은 통합 테스트 시에 사용
    • Mock은 순수한 Mockito 객체, MockBean은 Spring Bean을 Mocking할 때 사용
    • Mock은 주입받으려면 @InMocks를 사용, MockBean은 @Autowired로 자동 주입
    • Mock은 SpringContext와 무관, MockBean은 SpringContext에서 관리
    • MockBean은 각 테스트 클래스에서 실행될 때마다 서버가 새로 뜬다.
    • Mock은 service 단에서 repository를 mocking할 때 사용, MockBean은 controller 단에서 service를 mocking할 때 사용 (@WebMvcTest에서는 실제 빈을 주입하여야 하기 때문에 MockBean을 사용해야 함)
    • when()을 사용해서 given 값 관리
  • @Spy vs @SpyBean
    • Spy는 실제 객체의 메서드를 호출하면서, 특정 메서드만 mocking할 수 있다.
    • SpyBean도 Spy의 기능과 같지만, MockBean과 동일하게 Spring Context에서 관리한다는 차이점이 있다.
    • doreturn()을 사용해서 given 관리
  • @InjectMocks
    • 순수한 Mockito 객체를 자동으로 주입할 때 사용
    • @Mock과 @Spy를 주입해야 하는 객체에 사용

 


2) 각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치하고 싶으신가요?

 

사용자 생성과 게시물 생성에 필요한 내용이 겹칠 경우

  • 겹치는 내용이라면 중복 코드를 없앨 수 있고, 초기 설정값들이 공통되므로 인식하는데도 불편함이 없을 것 같다.
@BeforeEach
void setUp() {
1-1, 2-1, 3-1. 사용자1 생성에 필요한 내용 준비
1-2, 2-2, 3-2. 사용자1 생성

1-3, 2-3, 3-5. 사용자1의 게시물 생성에 필요한 내용 준비
1-4, 2-4, 3-6. 사용자1의 게시물 생성
}

@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-3. 사용자2 생성에 필요한 내용 준비
    3-4. 사용자2 생성

    3-7. 사용자1의 댓글 생성에 필요한 내용 준비
    3-8. 사용자1의 댓글 생성

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

    // then
    검증
}

 

사용자 생성과 게시물 생성에 필요한 내용이 겹치지 않고, 각 테스트마다 고유할 경우

  • 각 테스트마다 고유한 내용이라면 분리하여, 독립성을 유지하는 게 맞다.
  • 3번째 테스트에서는 사용자를 2번 생성하기에 코드 가독성 수준에서도 아래가 더 맞는 것 같다.
@BeforeEach 
void setUp() {
    // 레포지토리 초기화
} 

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

    // when
    1-6. 댓글 생성

    // then
    검증
}

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

    // when
    2-7. 댓글 수정

    // then
    검증
}

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

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

    // then
    검증        
}

 

[출처]