found multiple declarations of @BootstrapWith for test class 에러

onyoo·2023년 2월 6일
1

Spring-Boot

목록 보기
2/6

found multiple declarations of @BootstrapWith for test class 에러

@BootstrapWith이 중복으로 사용되어서 발생하는 에러

@SpringBootTest 와 @WebMvcTest 둘다 @BootstrapWith를 가지고 있는 어노테이션이다.

똑같은 어노테이션을 사용하는 어노테이션을 사용해서 발생한 문제

내 코드

package com.example.everytime.controller;

import com.example.everytime.domain.posts.Post;
import com.example.everytime.domain.posts.PostRepository;
import com.example.everytime.dto.PostSaveRequestDto;
import org.junit.After;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//@WebMvcTest(controllers = PostControllerTest.class) --> 에러가 발생한 부분
public class PostControllerTest {

    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private PostRepository postRepository;

    @After
    public void tearDown() throws Exception{
        postRepository.deleteAll();
    }

    @Test
    @Transactional
    public void Post_등록된다() throws Exception{
        //given
        String title = "title";
        String contents = "content";

        PostSaveRequestDto requestDto = PostSaveRequestDto.builder()
                .title(title)
                .contents(contents)
                .build();

        String url = "http://localhost:"+ port + "/api/v1/posts";

        //when
        ResponseEntity<UUID> responseEntity = restTemplate.postForEntity(url,requestDto, UUID.class);

        //then
        assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(responseEntity.getBody()).isNotNull();

        List<Post> all = postRepository.findAll();
        assertThat(all.get(0).getTitle()).isEqualTo(title);
        assertThat(all.get(0).getContents()).isEqualTo(contents);
    }

}
  • WebMvcTest 는 JPA 기능이 작동하지 않기 때문에 JPA 기능까지 한꺼번에 테스트해야할 경우 SpringBootTest 를 사용하는게 적절하다.

두 어노테이션이 어느 경우에 사용되는지, 어떤 용도로 사용되고 있는지 간단하게 알아보면

@SpringBootTest

Untitled

공식문서에 따르면 @BootStrapWith 가 포함되어있는 것을 확인할 수 있고.

스프링부트를 기반으로 한 테스트를 위한 클래스를 지정하는 어노테이션이다.

다음과 같은 특징을 가지고있다.

  • 전체 컨텍스트를 로드하여 빈을 주입하기 때문에 속도가 느리다
  • 수많은 스프링 빈을 등록하여 테스트에 필요한 것을 주입한다
  • 사용자 환경 속성을 지정할 수 있다
  • 애플리케이션의 모든 설정을 로드함

이러한 특징때문에 통합 테스트를 할 때 많이 사용하며, 테스트에 필요한 빈만을 등록하여 테스트를 진행하고자 하기 위해서는 @WebMvcTest 를 사용하는 것이 더 효율적임.

@WebMvcTest

Untitled

MVC를 위한 테스트이며, 웹에서 테스트하기 힘든 컨트롤러를 테스트하는데 적합하다.

이 어노테이션을 사용하면 MVC 테스트와 관련된 어노테이션만 활성화 된다. 이를테면 @Controller, @ControllerAdvice, @JsonComponent, Converter/GenericConverter, Filter 등등.. 그렇기 때문에 @SpringBootTest 어노테이션보다 가볍게 테스트할 수 있다.

전체 애플리케이션 구성을 로드하고, mockMvc를 사용할 경우 SpringBootTest를 사용하는 것을 고려하는게 적절하다.

profile
반갑습니다 ! 백엔드 개발 공부를 하고있습니다.

0개의 댓글