-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* #65 - feat: 게시글 좋아요 생성 로직 구현 PostLike 객체 내부에서 post.increaseLikeCount() 를 호출하는 형식으로 함 * #65 - test: 서비스 테스트와 컨트롤러 테스트 구현
- Loading branch information
Showing
7 changed files
with
242 additions
and
4 deletions.
There are no files selected for viewing
38 changes: 38 additions & 0 deletions
38
src/main/java/cotato/bookitlist/post/controller/PostLikeController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package cotato.bookitlist.post.controller; | ||
|
||
import cotato.bookitlist.config.security.jwt.AuthDetails; | ||
import cotato.bookitlist.post.service.PostLikeService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder; | ||
|
||
import java.net.URI; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/posts/{post-id}/likes") | ||
public class PostLikeController { | ||
|
||
private final PostLikeService postLikeService; | ||
|
||
@PostMapping | ||
public ResponseEntity<Void> registerLike( | ||
@PathVariable("post-id") Long postId, | ||
@AuthenticationPrincipal AuthDetails details | ||
) { | ||
Long postLikeId = postLikeService.registerLike(postId, details.getId()); | ||
|
||
URI location = ServletUriComponentsBuilder | ||
.fromCurrentRequest() | ||
.path("/{id}") | ||
.buildAndExpand(postLikeId) | ||
.toUri(); | ||
|
||
return ResponseEntity.created(location).build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
src/main/java/cotato/bookitlist/post/repository/PostLikeRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package cotato.bookitlist.post.repository; | ||
|
||
import cotato.bookitlist.post.domain.PostLike; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface PostLikeRepository extends JpaRepository<PostLike, Long> { | ||
} |
32 changes: 32 additions & 0 deletions
32
src/main/java/cotato/bookitlist/post/service/PostLikeService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package cotato.bookitlist.post.service; | ||
|
||
import cotato.bookitlist.member.domain.Member; | ||
import cotato.bookitlist.member.repository.MemberRepository; | ||
import cotato.bookitlist.post.domain.Post; | ||
import cotato.bookitlist.post.domain.PostLike; | ||
import cotato.bookitlist.post.repository.PostLikeRepository; | ||
import cotato.bookitlist.post.repository.PostRepository; | ||
import jakarta.persistence.EntityNotFoundException; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@Transactional | ||
@RequiredArgsConstructor | ||
public class PostLikeService { | ||
private final PostRepository postRepository; | ||
private final PostLikeRepository postLikeRepository; | ||
private final MemberRepository memberRepository; | ||
|
||
public Long registerLike(Long postId, Long memberId) { | ||
Post post = postRepository.findById(postId) | ||
.orElseThrow(() -> new EntityNotFoundException("책을 찾을 수 없습니다.")); | ||
Member member = memberRepository.getReferenceById(memberId); | ||
|
||
PostLike postLike = PostLike.of(member, post); | ||
postLike.increasePostLikeCount(); | ||
|
||
return postLikeRepository.save(postLike).getId(); | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
src/test/java/cotato/bookitlist/post/controller/PostLikeControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package cotato.bookitlist.post.controller; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import cotato.bookitlist.annotation.WithCustomMockUser; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.test.context.ActiveProfiles; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; | ||
|
||
@Transactional | ||
@SpringBootTest | ||
@AutoConfigureMockMvc | ||
@DisplayName("게시글 좋아요 컨트롤러 테스트") | ||
@ActiveProfiles("test") | ||
class PostLikeControllerTest { | ||
|
||
@Autowired | ||
MockMvc mockMvc; | ||
|
||
@Autowired | ||
ObjectMapper objectMapper; | ||
|
||
@Test | ||
@WithCustomMockUser | ||
@DisplayName("게시글 좋아요를 생성한다") | ||
void givenPostId_whenRegisteringPostLike_thenRegisterPostLike() throws Exception { | ||
//given | ||
|
||
//when & then | ||
mockMvc.perform(post("/posts/1/likes") | ||
.contentType(MediaType.APPLICATION_JSON)) | ||
.andExpect(status().isCreated()) | ||
.andExpect(header().exists("Location")) | ||
; | ||
} | ||
|
||
@Test | ||
@WithCustomMockUser | ||
@DisplayName("존재하지 않는 게시글에 좋아요를 요청하면 에러를 반환한다.") | ||
void givenNonExistedPostId_whenRegisteringPostLike_thenReturnErrorResponse() throws Exception { | ||
//given | ||
|
||
//when & then | ||
mockMvc.perform(post("/posts/10/likes") | ||
.contentType(MediaType.APPLICATION_JSON)) | ||
.andExpect(status().isNotFound()) | ||
.andExpect(jsonPath("$.message").value("책을 찾을 수 없습니다.")) | ||
; | ||
} | ||
|
||
|
||
|
||
} |
82 changes: 82 additions & 0 deletions
82
src/test/java/cotato/bookitlist/post/service/PostLikeServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package cotato.bookitlist.post.service; | ||
|
||
import cotato.bookitlist.book.domain.entity.Book; | ||
import cotato.bookitlist.config.security.oauth.AuthProvider; | ||
import cotato.bookitlist.member.domain.Member; | ||
import cotato.bookitlist.member.repository.MemberRepository; | ||
import cotato.bookitlist.post.domain.Post; | ||
import cotato.bookitlist.post.domain.PostLike; | ||
import cotato.bookitlist.post.repository.PostLikeRepository; | ||
import cotato.bookitlist.post.repository.PostRepository; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.junit.jupiter.MockitoExtension; | ||
import org.springframework.test.util.ReflectionTestUtils; | ||
|
||
import java.time.LocalDate; | ||
import java.util.Optional; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.ArgumentMatchers.anyLong; | ||
import static org.mockito.BDDMockito.given; | ||
import static org.mockito.BDDMockito.then; | ||
|
||
@DisplayName("게시글 좋아요 서비스 테스트") | ||
@ExtendWith(MockitoExtension.class) | ||
class PostLikeServiceTest { | ||
|
||
@InjectMocks | ||
PostLikeService sut; | ||
@Mock | ||
PostRepository postRepository; | ||
@Mock | ||
PostLikeRepository postLikeRepository; | ||
@Mock | ||
MemberRepository memberRepository; | ||
|
||
@Test | ||
@DisplayName("게시글 좋아요를 생성한다.") | ||
void givenPostId_whenRegisteringPostLike_thenRegisterPostLike() throws Exception { | ||
//given | ||
Long postId = 1L; | ||
Long memberId = 1L; | ||
Post post = createPost(); | ||
Member member = createMember(); | ||
|
||
given(postRepository.findById(anyLong())).willReturn(Optional.of(post)); | ||
given(memberRepository.getReferenceById(anyLong())).willReturn(member); | ||
given(postLikeRepository.save(any(PostLike.class))).willReturn(createPostLike(post, member)); | ||
|
||
//when | ||
sut.registerLike(postId, memberId); | ||
|
||
//then | ||
assertThat(post.getLikeCount()).isEqualTo(1); | ||
then(postRepository).should().findById(anyLong()); | ||
then(memberRepository).should().getReferenceById(anyLong()); | ||
then(postLikeRepository).should().save(any(PostLike.class)); | ||
} | ||
|
||
Post createPost() { | ||
return Post.of(createMember(), createBook(), "title", "content"); | ||
} | ||
|
||
Book createBook() { | ||
return Book.of("title", "author", "pubisher", LocalDate.now(), "description", "link", "isbn13", 10000, "cover"); | ||
} | ||
|
||
Member createMember() { | ||
return new Member("email", "name", "oauth2Id", AuthProvider.KAKAO); | ||
} | ||
|
||
PostLike createPostLike(Post post, Member member) { | ||
PostLike postLike = PostLike.of(member, post); | ||
ReflectionTestUtils.setField(postLike, "id", 1L); | ||
return postLike; | ||
} | ||
|
||
} |