kkkkkkkkkkkk 2022. 3. 31. 14:21

🕶  업데이트 기능을 만들어 봅시다!.

  • Controller 클래스에 기능 추가해보기!
@PutMapping("/api/v1/posts/{id}") -> http put() 사용합니다.
public Long update(@PathVariable Long id, @RequestBody PostsUpdateRequestDto requestDto) {
    return postsService.update(id, requestDto);
}

updateRequestDto 클래스를 활용하여 업데이트 할 데이터를 담아서 엔티티에 전달하게 합니다.

  • updateRequestDto 클래스 생성해보기!
@Getter
@NoArgsConstructor
public class PostsUpdateRequestDto{

    private String title;
    private String content;

    @Builder
    public PostsUpdateRequestDto(String title, String content) {
        this.title = title;
        this.content = content;
    }
}
  • Service 클래스에 update() 기능 추가해보기!
@Transactional
public Long update(Long id, PostsUpdateRequestDto requestDto) {
    Posts entity = getEntity(id);
    entity.update(requestDto.getTitle(), requestDto.getContent());
    return entity.getId();
}

트랜잭션 실패로 인해 데이터의 무결성과 지속성 영속성을 보장하기 위해 @Transactional 를 사용합니다.

코드를 보면 업데이트를 하는 쿼리문은 보이질 않습니다.

 

😭  쿼리문이 없는데 업데이트가 어떻게 되나요????

 

JPA 의 영속성 컨텍스트 의 특징으로 업데이트 쿼리문을 안날려도 업데이트가 됩니다. 영속성 컨텍스트 란 엔티티를 영구 저장하는 환경 이라고 합니다.

JPA 의 엔티티 매니저가 활성화 된 상태 (Spring Data JPA 를 사용하면 디폴트 값이 활성 상태입니다.) 로 트랜잭션에서 데이터베이스에서 데이터를 가져오면 이 데이터는 영속성 컨텍스트가 유지된 상태입니다.

이 상태에서 해당 데이터의 값을 변경하면 트랜잭션이 끝나는 시점에 해당 테이블에 반영이 되어 업데이트 쿼리문을 날리지 않아도 업데이트가 될 수 있는 겁니다.

 

  • Entity 클래스에 update() 기능 추가!!
public void update(String title, String content) {
    this.title = title;
    this.content = content;
}
  • getEntity() 살펴보기!
private Posts getEntity(Long id) {
    return postsRepository.findById(id)
            .orElseThrow(()-> new IllegalArgumentException("존재하는 게시글이 없습니다."));
}

findById() 기능에서도 중복된 코드를 사용하므로 메서드를 따로 추출하여 리펙토링을 하였습니다.

🕶  테스트 코드를 작성해봅시다.

  • updateRequestDto 클래스 테스트
@Test
@DisplayName("PostsUpdateRequestDto_TEST")
void PostsUpdateRequestDtoTest() {
    // given
    String expectedTitle = "테스트";
    String expectedContent = "테스트 중 입니다.";

    // when
    PostsUpdateRequestDto requestDto = PostsUpdateRequestDto.builder()
                    .title("테스트")
                    .content("테스트 중 입니다.")
                    .build();

    // then
    assertThat(requestDto.getTitle()).isEqualTo(expectedTitle);
    assertThat(requestDto.getContent()).isEqualTo(expectedContent);
}
  • Service 클래스 update 테스트
    @BeforeEach
    public void beforeEach() {
        PostsSaveRequestDto dto = PostsSaveRequestDto.builder()
                .title("테스트1")
                .content("테스트 중 입니다.1")
                .author("홍길동1")
                .build();

        postsService.save(dto);
    }

    @AfterEach
    public void afterEach() {
        postsRepository.deleteAll();
    }

    @Test
    @DisplayName("Update_된다")
    void update() {
        // given
        Long findId = 1L;

        String expectedTitle = "테스트 수정";
        String expectedContent = "테스트 중 입니다. 수정";

        PostsUpdateRequestDto updateRequestDto = PostsUpdateRequestDto.builder()
                            .title(expectedTitle)
                            .content(expectedContent)
                            .build();

        // when
        postsService.update(findId, updateRequestDto);

        // then
        PostsResponseDto updatePosts = postsService.findById(1L);

        assertThat(updatePosts.getTitle()).isEqualTo(expectedTitle);
        assertThat(updatePosts.getContent()).isEqualTo(expectedContent);

}

테스트 코드가 실행 되기 전에 domain 의 데이터 값을 저장 하여 update 기능을 검증 합니다.

  • Controller 클래스 테스트
@BeforeEach
public void beforeEach() {
    postsRepository.save(PostsSaveRequestDto.builder()
                .title("테스트1")
                .content("테스트 중 입니다.1")
                .author("홍길동1")
                .build()
                .toEntity());
}

@AfterEach
public void afterEach() {
    postsRepository.deleteAll();
}

@Test
@DisplayName("Update_된다!!!!")
void update() {
    // given
    Posts posts = postsRepository
            .findById(1L)
            .orElseThrow(()-> new IllegalArgumentException("존재하지 않습니다."));

    Long updatedId = posts.getId();
    String expectedTitle = "테스트2";
    String expectedContent = "테스트 중 입니다.2";

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

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

    // when
    ResponseEntity<Long> responseEntity =
            restTemplate.exchange(url, HttpMethod.PUT, postsUpdateRequestDtoHttpEntity, 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);

}

테스트 코드가 실행 되기 전에 domain 의 데이터 값을 저장 하여 update 기능을 검증 합니다.

 

🕶  로그를 살펴보자!

업데이트 쿼리가 실행 되는 것을 살펴 볼 수 있습니다.!