[Project] Test Code 작성

조수훈·2023년 9월 27일
0

Project

목록 보기
2/8
post-thumbnail

본 포스팅은 스스로 공부한 내용을 정리하고 기록하기 위하여 올리는 내용이며, 잘못된 내용이 있을 수도 있음을 미리 밝힙니다. 잘못된 내용이 있거나, 더 좋은 방법이 있다면 댓글로 남겨주시기 바랍니다.


현재까지 프로젝트를 진행하면서 귀찮다는 이유로 test code 의 작성을 미뤄왔고, 항상 다음과 같은 순서로 완성된 Restful api 를 검증하였습니다.

  1. 코드 작성
  2. 애플리케이션 실행
  3. PostMan 으로 Restful API 요청
  4. log 나 Print 로 결과확인
  5. 애플리케이션 종료
  6. 코드 수정

하지만 프로젝트가 점점 진행되면서 다음과 같은 순서를 지속하기가 어려워졌고, Test code 를 작성하기로 결정했습니다.

Test code 도입후 테스트 과정은 다음과 같습니다.

  1. 코드를 수정
  2. 테스트 코드 실행
  3. 결과 확인

이처럼 테스트 코드는 만들어진 API 를 검증하는데 시간절약을 할수있습니다.
테스트 코드를 만들때 데이터를 미리 기입하고, 테스트가 끝날때의 정리하는 행동등을 만들어줄수있습니다.

테스트 코드 작성


라이브러리 추가

testImplementation('org.springframework.boot:spring-boot-starter-test')

@SpringBootTest

@SpringBootTest 를 이용하여 전체 애플리케이션의 컨텍스트를 생성하도록 요청 할수있습니다. 모든 빈들을 스캔하고 애플리케이션 컨텍스트 생성하므로 손쉽게 통합 테스트를 위한 환경을 준비해줄수있습니다.

@SpringBootTest는 기본적으로 모든 빈을 탐색하고 등록합니다. 따라서 특정 계층만 테스트가 필요한 상황에서 @SpringBootTest를 사용하면 불필요하게 무거워지고 시간이 오래 걸리게 됩니다. 그래서 스프링은 특정 부분만 테스트 할수 있도록 sliceTest를 위한 어노테이션들을 제공합니다. slice Test는 unit Test 가 아니라는 점에 주의해야 합니다.
다음은 @SpringBootTest 를 활용하여 service 레이어를 test 한 코드입니다.

@SpringBootTest
@ActiveProfiles("test")
@Transactional
@SqlGroup({
        @Sql(value = "/sql/user-service-test-data.sql", executionPhase = ExecutionPhase.BEFORE_TEST_METHOD),
})
public class ImageServiceTest {

    @Autowired
    private ImageService imageService;

    @MockBean
    private S3Util s3Util;

    @Mock
    private MultipartFile multipartFile;

    @Test
    void uploadImage_로이미지를업로드할수있다() throws IOException {
        //given
        when(multipartFile.getContentType()).thenReturn("image/jpeg");
        when(s3Util.uploadFile(multipartFile)).thenReturn("image123.jpg");
        when(s3Util.getImageUrl("image123.jpg")).thenReturn("https://example.com/image123.jpg");
        //when
        String imageUrl = imageService.uploadImage(multipartFile);

        //then
        Assertions.assertThat(imageUrl).isNotEmpty();

    }
}

SliceTest 를 위한 어노테이션

@WebMvcTest

@WebMvcTest를 사용하여 컨텍스트의 웹 계층만 생성하도록 요청할수 있습니다. @WebMvcTest는 애플리케이션 컨텍스트를 만들 때 컨트롤러와 연관된 빈들만을 제한적으로 찾아서 등록합니다. 그러므로 일반적인 @Component나 @ConfigurationProperties 빈들은 스캔되지 않습니다.
@WebMvcTest 내부에는 @AutoConfigureMockMvc가 들어있습니다. 그러므로 @Autowired 로 MockMvc를 주입받을 수 있습니다.
( @AutoConfigureMockMvc 를 이용하여 편리한 빌드 클래스 MockMvc를 통해 HTTP 요청을 DispatcherServlet으로 보낼수있습니다.)

@WebMvcTest(UserController.class)
@ActiveProfiles(profiles = "test")
@Import(SecurityConfig.class)
@AutoConfigureMockMvc
class UserControllerTest {


    @Autowired
    private MockMvc mvc;

    @MockBean
    private UserService userService;

    @MockBean
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @MockBean
    private JwtTokenProvider jwtTokenProvider;

    @MockBean
    private KafkaProducerService kafkaProducerService;


    private final ObjectMapper objectMapper = new ObjectMapper();


    @Test
    public void 회원가입() throws Exception {
        //given
        String email = "fddfdassa@naver.com";
        String password = "1234sda";
        String nickName = "suhoon";
        CreateUserRequest createUserRequest = new CreateUserRequest(email, nickName, password, null);

        String body = objectMapper.writeValueAsString(createUserRequest);
        BDDMockito.doNothing().when(kafkaProducerService).sendMessage(any());
        //when
        mvc.perform(
                        post("/sign-up")
                                .contentType(MediaType.APPLICATION_JSON)
                                .content(body))
                .andExpect(status().is(200));

        //then

    }
 }

@DataJpaTest

@DataJpaTest 는 JPA 레포지토리 테스트를 하기위해 만들어졌습니다. 기본적으로 @Entity 가 있는 엔티티 클래스들을 스캔하며 테스트를 위한 TestEntityManger를 사용해 JPA 레포지토리들을 설정해줍니다. @DataJpaTest에는 @Transactional 어노테이션이 들어가있어서 기본적으로 모든 테스트가 롤백됩니다. 롤백을 원하지 않는다면 @Rollback(false)를 추가하도록 합니다.

@DataJpaTest 안에는 @AutoConfigureTestDataBase가 내장되어있습니다.
@AutoConfigureTestDatabase 어노테이션의 기본 설정값인 Replace.Any를 사용하면 기본적으로 내장된 임베디드 데이터베이스를 사용한다. 따라서 Test를 내장 임베디드 데이터베이스가 아닌 실제 데이터베이스를 사용해서 할것이라면, @AutoConfigureTestDatabase(replace = Replace.NONE)
이 옵션을 꼭 넣어주어야 합니다.

@DataJpaTest(showSql = true)
@AutoConfigureTestDatabase(replace = Replace.NONE)
@ActiveProfiles("test")
public class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;


    @Test
    void db가_잘연결되어있다() {
        //given
        UserEntity userEntity = UserEntity.builder()
                .id(10L)
                .email("suhoon@naver.com")
                .build();

        //when
        UserEntity user = userRepository.save(userEntity);

        //then
        Assertions.assertThat(user.getEmail()).isEqualTo("suhoon@naver.com");
    }
}




Reference

SpringBoot TEST DOCS
TEST code 작성예시
SpringBoot TEST 어노테이션
관련 유튜브 영상
스프링 부트 통합테스트 방법과 팁

profile
잊지 않기 위해 기록하기

0개의 댓글