[스프링부트와 AWS로 혼자 구현하는 웹 서비스] 등록/수정/조회 API 테스트

세이라·2023년 7월 22일
0

스터디를 통해 스프링부트와 AWS로 혼자 구현하는 웹 서비스(저자 이동욱) 서적을 공부하는 중입니다.

공부/실습한 내용을 정리한 포스팅입니다.
책에 모르는 부분이 있으면 구글링하거나 챗gpt에 물어봐서 보충하였습니다.
(아직 초보라 모르는 부분이 많아 이것저것 다 적었습니다.)

참고한 사이트 출처는 포스팅 맨 하단에 적었습니다.

PostsApiControllerTest 코드

package com.webservice.springboot.springboot_board.web;

import com.webservice.springboot.springboot_board.domain.posts.Posts;
import com.webservice.springboot.springboot_board.domain.posts.PostsRepository;
import com.webservice.springboot.springboot_board.web.dto.PostsSaveRequestDto;
import com.webservice.springboot.springboot_board.web.dto.PostsUpdateRequestDto;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

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

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PostsApiControllerTest {
    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private PostsRepository postsRepository;

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

    @Test
    public void Posts_등록된다() throws Exception{
        //given
        String title="title";
        String content="content";
        PostsSaveRequestDto requestDto = PostsSaveRequestDto.builder()
                .title(title)
                .content(content)
                .author("author")
                .build();
        String url = "http://localhost:"+port+"/api/v1/posts";

        //when
        ResponseEntity<Long> responseEntity
                = restTemplate.postForEntity(url, requestDto, Long.class);
        //then
        assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(responseEntity.getBody()).isGreaterThan(0L);

        List<Posts> all = postsRepository.findAll();
        assertThat(all.get(0).getTitle()).isEqualTo(title);
        assertThat(all.get(0).getContent()).isEqualTo(content);
    }

    @Test
    public void Posts_수정된다() throws Exception {
        //given
        Posts savedPosts = postsRepository.save(Posts.builder()
                .title("title")
                .content("content")
                .author("author")
                .build()
        );

        Long updatedId = savedPosts.getId();
        String expectedTitle = "title2";
        String expectedContent = "content2";

        PostsUpdateRequestDto requestDto =
                PostsUpdateRequestDto.builder()
                        .title(expectedTitle)
                        .content(expectedContent)
                        .build();
        String url="http://localhost:"+port+"/api/v1/posts/"+updatedId;

        HttpEntity<PostsUpdateRequestDto> requestEntity = new HttpEntity<>(requestDto);

        //when
        ResponseEntity<Long> responseEntity = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, Long.class);

        //then
        assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(responseEntity.getBody()).isGreaterThan(0L);

        List<Posts> all = postsRepository.findAll();
        assertThat(all.get(0).getTitle()).isEqualTo(expectedTitle);
        assertThat(all.get(0).getContent()).isEqualTo(expectedContent);
    }
}

PostsApiControllerTest 설명

@SpringBootTest

  • @WebMvcTest의 경우, JPA 기능 작동X Controller와 ControllerAdvice 등 외부 연동과 관련된 부분만 활성화되어 JPA 기능까지 테스트 시 @SpringBootTest 사용
  • 테스트 시 Application Context 로드하기 위해 사용. 테스트 환경에서 Spring Boot Application의 Context가 로드되고, 테스트에 필요한 Bean과 설정정보를 사용할 수 있게 됨.

webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT

  • webEnvironment란, 테스트 웹 환경을 설정하는 속성.
    : default는 SpringBootTest.WebEnvironment.MOCK. 실제 Servlet Container를 띄우지않고 Mock 서블릿 제공. 실제 Servlet 환경X 보통 MockMvc 주입 받아 테스트.
  • Spring Boot의 내장 서버를 랜덤 포트로 띄우기 위해선 webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT 이용. 실제로 테스트를 위한 Servlet Container를 띄움. TestRestTemplate 주입 받아 테스트.(TestRestTemplate를 열려있는 포트로 자동으로 등록. 열려있는 포트가 없다면 TestRestTemplate Bean 등록을 못 함)

※ Mock 서블릿 : 실제가 아닌 가짜 서블릿. 테스트를 위해 사용.

@LocalServerPort

  • 이 annotation을 통해, 테스트에 포트 번호 삽입 가능.

TestRestTemplate

  • REST API의 Test 최적화 위한 클래스
  • HTTP 요청 후 데이터를 응답 받을 수 있는 템플릿 객체며 ResponseEntity와 함께 사용됨.
  • Header, Content-Type 등을 설정하여 API 호출

postForEntity 메서드

POST 요청을 보내고 결과로 ResponseEntity로 반환받는다

	public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType,
			Object... urlVariables) throws RestClientException {
		return this.restTemplate.postForEntity(url, request, responseType, urlVariables);
	}

Params:
url – the URL
request – the Object to be POSTed, may be null
responseType – the response type to return
urlVariables – the variables to expand the template

ResponseEntity<Long> responseEntity
	= restTemplate.postForEntity(url, requestDto, Long.class);

exchange 메서드

HTTP 헤더를 새로 만들 수 있고 어떤 HTTP 메서드도 사용가능하다

	public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
			Class<T> responseType, Object... urlVariables) throws RestClientException {
		return this.restTemplate.exchange(url, method, requestEntity, responseType, urlVariables);
	}

Params:
url – the URL
method – the HTTP method (GET, POST, etc)
requestEntity – the entity (headers and/or body) to write to the request, may be null
responseType – the type of the return value urlVariables – the variables to expand in the template

	ResponseEntity<Long> responseEntity = 
    	restTemplate.exchange(url, HttpMethod.PUT, requestEntity, Long.class);

ResponseEntity

  • Spring 제공 클래스 중 HttpEntity 클래스가 존재. 이는 HTTP 요청/응답 시 HTTP 헤더와 바디 포함 클래스인데, ResponseEntity,RequestEntity는 이 HttpEntity를 상속 받음.
  • ResponseEntity는 사용자의 응답 데이터를 가지며, HTTP Status,Header,Body를 포함.
  • ResponseEntity<T>에서 T는 body type.

출처

[Spring Boot] ResponseEntity와 TestRestTemplate
스프링 부트 테스트 - 내장 서버 랜덤 포트로 띄우기
[Spring] @SpringBootTest의 webEnvironment와 @Transactional
Mock 이란?
[일지] TestRestTemplate 로 테스트 하면서 궁금했던 점(feat :NoSuchBeanDefinitionException)
Spring Boot Tips, Tricks and Techniques(스프링 부트 팁, 트릭, 기술)
[spring] 스프링에서 사용하는 RestTemplate - http 라이브러리

0개의 댓글