hanghae99/프로젝트

[테스트코드/단위테스트] 테스트코드 작성 시 겪은 문제와 해결 방법 2탄

욘아리 2024. 2. 27. 00:00

이전 포스팅에서 언급한 대로, 테스트 코드에 대한 이해 부족으로 controller 단위 테스트를 진행하려다가 통합 테스트로 진행했었다. 내가 작성한 테스트 코드는 각 controller의 엔드포인트의 동작을 검증하며, MockMvc를 사용하여 HTTP 요청 및 응답을 확인한다. 또한, 데이터베이스와 상호작용은 데이터를 테스트마다 미리 설정하고 JPA Test를 사용하여 테스트용 데이터 베이스에서 실행된다.

 

❓문제 상황

통합 테스트는 내가 작성한 코드가 아닌 외부에서 오류가 발생할 수 있음.
👉 이에 핵심 로직인 비즈니스 로직은 서비스 단에서 다른 요인들을 배제하고 독립적으로 테스트되어야 함.

 

프로젝트를 마무리하는 시점에서 통합 테스트도 3일에 걸쳐 완성했었는데, 서비스 테스트(단위 테스트)도 전부 진행하기엔 무리가 있다고 생각했다. 통합 테스트 했으니까 포기할까도 생각했지만 꼭 작성해야 한다고 생각이 들어 핵심 기능인 게시물 로직만 중점적으로 다루기로 했다. 

 

💡해결 방법

독립적으로 테스트하기 위해 Mockito를 활용하여 서비스 단에서의 테스트 코드를 작성했다.

아래는 게시물 조회 성공에 대한 코드이다.

@ExtendWith(MockitoExtension.class)
class PostServiceImplTest {

    @Mock
    PostRepository postRepository;

    @Mock
    UserRepository userRepository;
    
    @InjectMocks
    PostServiceImpl postService;

    @Test
    @DisplayName("게시물 조회 성공")
    void getPost_success() {
    	// 1. 테스트할 게시물의 ID와 모의 객체를 생성
        Long postId = 1L;
        Post mockPost = new Post(new User(), "title", "content");
        
        // 2. when을 사용하여 postRepository.findById 메서드 호출 시 모의 객체를 반환하도록 설정
        when(postRepository.findById(postId)).thenReturn(Optional.of(mockPost));
		
        // 3. 테스트 대상 메서드를 호출하고 결과 저장
        PostResponse result = postService.getPost(postId);
		
        // 4. postRepository.findById 메서드가 postId로 1번 호출되었는지 확인
        verify(postRepository, times(1)).findById(postId);
		
        // 5. 결과 객체의 값이 모의 객체의 값과 일치하는지 확인
        assertThat(result.getTitle()).isEqualTo(mockPost.getTitle());
        assertThat(result.getContent()).isEqualTo(mockPost.getContent());
    }
}
  1. @ExtendWith(MockitoExtension.class): Mockito를 사용하여 테스트를 진행하기 위해 필요한 확장 지정
  2. @Mock: PostRepository와 UserRepository의 Mock 객체를 생성, 실제 메서드 호출을 대신하여 테스트에서 원하는 동작 정의
  3. @InjectMocks: PostServiceImpl 객체를 생성하면서 위에서 생성한 Mock 객체들을 주입, 테스트 대상인 postService에서 Mock 객체 사용 가능

 

📝 삽질 기록

❗게시물 작성자와 사용자의 일치 여부를 확인하는 곳에서 발생한 문제

 

게시물 수정과 삭제 할 때, 사용자의 id와 작성자의 id를 비교해야 했다. 하지만 실제 사용자 객체는 id가 자동으로 생성되어 어떻게 처리해야 할지 막막했다. (코드를 싹 갈아엎어야하는 줄 알고 겁먹고 그냥 접어야 하나..? 생각도 했다..ㅎㅎ)

게시물 수정 service 코드
게시물 수정 서비스 테스트 코드에 user를 설정한 코드

 

고민한 게 무색할 정도로 생각보다 간단한 방법인 사용자에 임의의 id 값을 지정해 주니 문제가 해결되었다.

ReflectionTestUtils.setField(user, "id", 1L);

 

ReflectionTestUtils.setField는 Spring 프레임워크에서 제공하는 유틸리티 메서드 중 하나로, 리플렉션(Reflection)을 사용하여 객체의 필드 값을 설정하는 데에 사용된다.

 

이 문제를 해결하고 나니 다른 문제들은 빠르게 해결하면서 지나갈 수 있었다.

뿌듯한 캡쳐✌️

 

✨👩‍💻 ✨

멘토링 피드백을 받고 잠시 멍했었지만, 피드백을 받을 수 있어서 감사했다. 직접 통합 테스트 코드도 작성해 봤기 때문에 어떤 점이 문제인 지 이해할 수 있었고, 서비스 테스트 코드는 (게시물 로직 하나뿐이지만..) 이전보다 수월하게 작성할 수 있었다.
다음부터는 개발을 완료한 후가 아니라 기능을 구현할 때마다 테스트 코드를 작성하는 방식으로 할 수 있을 것 같다. (그렇게 해야만 한다.)