hyeonga_code

PreProject_07_Controller Test (TestRestTemplate) 본문

Project_HYEONGARL

PreProject_07_Controller Test (TestRestTemplate)

hyeonga 2024. 5. 21. 05:59
반응형

 

 

목표.

Controller 코드를 테스트하는 ControllerTest 코드를 작성하고자했다.

 

 

문제점.

유사한 환경의 다른 사람의 작업을 참고하려다 보니, 이리저리 혼합되어 이도저도 아닌 코드가 되어버렸다.

결국 @SpringBootTest 어노테이션과 @WebMvcTest 어노테이션을 같이 작성하는 코드가 되어버렸다.

테스트에 대해 어렴풋이 알고 있어서 발생한 문제점이라고 생각된다.

통합테스트와 단위테스트를 이해했지만, 이론은 이론이고 적용은 또다른 문제였다.

 

@SpringBootTest  vs @WebMvcTest

@SpringBootTest

전체 스프링 애플리케이션 컨텍스트를 로드하여 테스트한다.

실제 애플리케이션과 동일한 방식으로 테스트를 수행할 수 있다.

실제로 실행 중인 애플리케이션과 비슷한 테스트를 작성할 때 유용한 테스트로 통합 테스트나 엔드투엔드 테스트를 작성할 때 사용된다.

 

@SpringBootTest
class ApplicationIntegrationTests {
    @Test
    void contextLoads() {
    	//애플리케이션 컨텍스트 로드 테스트
    }
    
    // 기타 통합 테스트
}

 

@WebMvcTest

웹 MVC 컨트롤러를 테스트한다.

웹 계층을 테스트하는 데 필요한 것만 로드한다.  (웹 컨트롤러, 필터, 컨트롤러 어드바이스)

데이터베이스나 보안과 같은 빈은 로드되지 않는다.

@WebMvcTest(Controller.class)
class ControllerTests {
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    void testMethod() throws Exception {
        mockMvc.perform(get("/url"))
            .andExpect(status().isOk());
    }
}

 

@SpringBootTest : 전체 애플리케이션 컨텍스트를 로드하여 테스트하여 속도가 느릴 수 있다.

@WebMvcTest : 웹 MVC 레이어만 로드하여 컨트롤러 관련 빈만 테스트하여 빠르고 가벼울 수 있다.

 

다른 방법.

Controller TestRestTemplate 을 사용하여 테스트한다.

Service MockMvc 를 사용하여 테스트 한다.

Controller 테스트의 경우 통합 테스트를 Service의 경우 단위 테스트를 진행하는 것이 바람직하다.

 

Controller 테스트의 경우

사용자가 실제로 요청하는 대로 애플리케이션이 응답하는지 확인하는 테스트로 특정 엔드포인트에 대한 테스트를 진행한다. 컨트롤러와 컨트롤러 간의 통합 테스트를 포함하고 사용자 시나리오에 가까운 테스트를 수행하여 실제 동작을 이해할 수 있다.

 

Service 테스트의 경우

개별 서비스 레이어의 비즈니스 로직을 테스트한다. 각 메소드에 대해 입력에 대한 출력을 확인하는 과정으로 서비스 내부를 테스트한다. 

 

통합 테스트의 경우 성공하는 경우를 테스트하고 단위 테스트의 경우 입력에 따라 실패하는 경우까지 세세하게 테스트하는 것이 좋다.

 

단위테스트에서 1) 예외 상황 테스트, 2) 경계 조건 테스트, 3) 다양한 시나리오 테스트 를 진행하는 것이 좋다.

 


TestRestTemplate

통합 테스트 시에 RESTful 웹 서비스를 호출하는 데 사용됩니다.
실제 HTTP 요청을 실행하고 결과를 검증할 수 있습니다.
RestTemplate의 확장된 형태로 테스트 용도로 적합합니다.

 

.getForObject ( url, responseType )

T response = restTemplate.getForObject(url, responseType)

 

주어진 url에 `GET` 요청을 보내고 응답을 객체로 변환하여 반환합니다.


.getForEntity ( url, responseType )

ResponseEntity<T> response = restTemplate.getForEntity(url, responseType);

 

주어진 url에 `GET` 요청을 보내고 응답을 ResponseEntity 객체로 반환합니다.


.postForObject ( url, request, responseType )

T response = restTemplate.postForObject(url, request, responseType);

 

주어진 url에 `POST`요청을 보내고 응답을 객체로 변환하여 반환합니다.


.postForEntity( url, request, responseType )

ResponseEntity<T> responseEntity = restTemplate.postForEntity(url, request, responseType);

 

주어진 url에 `POST`요청을 보내고 응답을 객체로 변환하여 반환합니다.


.put( url, request )

restTemplate.put(url, request);

 

주어진 url에 `PUT` 요청을 보냅니다.


.delete( url )

restTemplate.delete(url);

 

주어진 url에 `DELETE` 요청을 보냅니다.


.exchange( url, HttpMethod.GET, requestEntity, responseType )

restTemplate.exchange(url, HttpMethod.GET, requestEntity, responseType);

 

주어진 HTTP 메소드를 사용하여 요청을 보내고 응답을 ResponseEntity로 반환합니다.


.execute ( url, HttpMethod.GET, requestCallBack, responseType )

restTemplate.execute(url, HttpMethod.GET, requestCallBack, responseType);

 

주어진 uri 및 HTTP 메소드를 사용하여 요청을 보내고 응답을 응답 핸들러에 전달합니다.

 

 


JsonPath

Spring MVC Test에서 JSON 응답의 특정 필드나 값에 대한 검증을 수행합니다.

.value( data )

해당 JSON 경로에 있는 값이 주어진 값과 일치하는지 검증합니다.

 

.stringValue( "data" )

해당 JSON 경로에 있는 값이 문자열 형태로 주어진 값과 일치하는지 검증합니다.

 

.numberValue( n )

해당 JSON 경로에 있는 값이 숫자 형태로 주어진 값과 일치하는지 검증합니다.

 

.booleanValue( true/false )

해당 JSON 경로에 있는 값이 주어진 값과 일치하는지 검증합니다.

 

.isArray()

해당 JSON 경로에 있는 값이 배열인지 검증합니다.

 

.isMap()

해당 JSON 경로에 있는 값이 객체인지 검증합니다.

 

.exists()

해당 JSON 경로에 값이 존재하는지 검증합니다.

 

.doesNotExist()

해당 JSON 경로에 값이 존재하지 않는지 검증합니다.

 

.isEmpty()

해당 JSON 경로에 있는 배열이나 객체가 비어있는지 검증합니다.

 

.isNotEmpty()

해당 JSON 경로에 있는 배열이나 객체가 비어 있지 않은지 검증합니다.

 

 

 

 

- 처음 작성했던 Controller

// ControllerTest.java
@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    private RequestDTO request;
    private ResponseDTO response;
    private List<ResponseDTO> responseList;

    @Test   // 등록
    @DisplayName("POST /url : CREATE")
    void create() throws Exception {
        //given
        Url url = request.toEntity();
        String json = objectMapper.writeValueAsString(url);

        //when
        ResultActions action = mockMvc.perform(post("/url")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(json));

        //then
        action.andExpect(status().isCreated())
                //.andExpect(content().string(containsString("Test Title")))
                .andDo(print());
    }
    
    ..중략..
}

 

 

- 수정한 Controller

// ControllerTest.java
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ControllerTest {
    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate restTemplate;
    // (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 있어야 autowired 가능

    @Test   
    public void testCreate() {
        RequestDto request
                = new UrlRequestDto(...);

        ResponseEntity<ResponseDto> responseEntity
                = restTemplate.postForEntity("/url", request, ResponseDto.class);

        assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.CREATED);

        ResponseDto responseBody = responseEntity.getBody();
        assertThat(responseBody).isNotNull();
        assertThat(responseBody.getName()).isEqualTo("create.com");
        assertThat(responseBody.getTitle()).isEqualTo("create Title");
        assertThat(responseBody.getDescription()).isEqualTo("create Description");
    }
}

 

 

 

@SpringBootTest

테스트에 필요한 거의 모든 의존성을 제공합니다.

사용하는 경우 @ExtendWith 를 이미 포함하고 있습니다.

Autowired 를 허용하여 객체에 의존성을 주입합니다.


@AutoConfigureMocMvc

MocMVC를 제어하는 어노테이션입니다.

Mock : 테스트를 위해 실제 객체와 비슷한 객체를 만드는 것입니다.

같은 기능을 수행하는 어노테이션으로 @WebMvcTest가 있습니다. (가벼운 테스트로 @Controller 어노테이션만 테스트 가능)

@Service, @Repository 모두 테스트가 가능합니다.

 

@Autowired

SpringBootTest 어노테이션이 없는 경우 의존성이 주입되지 않아 null로 처리됩니다.

AutoConfigureMocMvc 어노테이션이 있어야 MockMvc 타입의 bean을 찾을 수 없다는 오류가 발생하지 않습니다.

 

@Test

JUnit5의 테스트를 수행합니다.

여러 테스트 케이스를 만들어 값 안에 추가하여 테스트를 할 수 있습니다.

반응형