스터디를 통해 스프링부트와 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
사용webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT
webEnvironment
란, 테스트 웹 환경을 설정하는 속성.SpringBootTest.WebEnvironment.MOCK
. 실제 Servlet Container를 띄우지않고 Mock 서블릿 제공. 실제 Servlet 환경X 보통 MockMvc 주입 받아 테스트.webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT
이용. 실제로 테스트를 위한 Servlet Container를 띄움. TestRestTemplate
주입 받아 테스트.(TestRestTemplate
를 열려있는 포트로 자동으로 등록. 열려있는 포트가 없다면 TestRestTemplate
Bean 등록을 못 함)※ Mock 서블릿 : 실제가 아닌 가짜 서블릿. 테스트를 위해 사용.
@LocalServerPort
TestRestTemplate
ResponseEntity
와 함께 사용됨.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
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 라이브러리