✨개요
🏃 목표
📢 좋아요 누르기 기능을 구현하자.
📢 요구사항
- 좋아요 누르기
- ‘좋아요’는 한번만 누를 수 있다. 중복으로 누르는 경우는 에러 처리.
- 좋아요 ERD

📜 접근방법
- 유저는 여러개의 좋아요를 남길 수 있다.
- 포스트는 여러개의 좋아요를 가질 수 있다.
- 좋아요는 하나의 포스트와 한명의 유저로 매핑된다.
✅ TO-DO
🔧 구현
좋아요 누르기 컨트롤러 테스트
좋아요 누르기 성공
<@Test
@DisplayName("좋아요 누르기 성공")
@WithMockUser
void like_SUCCESS() throws Exception {
when(likeService.like(any(), any()))
.thenReturn(likeResponse);
mockMvc.perform(post("/api/v1/posts/1/likes")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk());
}
좋아요 누르기 실패
@Test
@DisplayName("좋아요 누르기 실패(1) : 유저가 없는 경우")
@WithMockUser
void like_FAIL_user() throws Exception {
when(likeService.like(any(), any()))
.thenThrow(new AppException(ErrorCode.USERNAME_NOT_FOUND, ErrorCode.USERNAME_NOT_FOUND.getMessage()));
mockMvc.perform(post("/api/v1/posts/1/likes")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isNotFound());
}
@Test
@DisplayName("좋아요 누르기 실패(2) : 포스트가 없는 경우")
@WithMockUser
void like_FAIL_post() throws Exception {
when(likeService.like(any(), any()))
.thenThrow(new AppException(ErrorCode.POST_NOT_FOUND, ErrorCode.POST_NOT_FOUND.getMessage()));
mockMvc.perform(post("/api/v1/posts/1/likes")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isNotFound());
}
좋아요 누르기 서비스 테스트
좋아요 누르기 성공
@Test
@DisplayName("좋아요 누르기 성공")
void like_SUCCESS() {
when(userRepository.findByUserName(any()))
.thenReturn(Optional.of(user));
when(postRepository.findById(any()))
.thenReturn(Optional.of(post));
when(likeRepository.save(like))
.thenReturn(like);
assertDoesNotThrow(() -> likeService.like(user.getUserName(), post.getId()));
}
좋아요 누르기 실패
@Test
@DisplayName("좋아요 누르기 실패(1) : 유저가 없는 경우")
void like_FAIL_user() {
when(userRepository.findByUserName(any()))
.thenReturn(Optional.empty());
when(postRepository.findById(any()))
.thenReturn(Optional.of(post));
when(likeRepository.save(like))
.thenReturn(like);
AppException exception = assertThrows(AppException.class, () -> likeService.like(user.getUserName(), post.getId()));
assertEquals(ErrorCode.USERNAME_NOT_FOUND, exception.getErrorCode());
}
@Test
@DisplayName("좋아요 누르기 실패(2) : 포스트가 없는 경우")
void like_FAIL_post() {
when(userRepository.findByUserName(any()))
.thenReturn(Optional.of(user));
when(postRepository.findById(any()))
.thenReturn(Optional.empty());
when(likeRepository.save(like))
.thenReturn(like);
AppException exception = assertThrows(AppException.class, () -> likeService.like(user.getUserName(), post.getId()));
assertEquals(ErrorCode.POST_NOT_FOUND, exception.getErrorCode());
}
좋아요 컨트롤러 구현
LikeController
@RestController
@RequestMapping("/api/v1/posts/{postId}/likes")
@RequiredArgsConstructor
public class LikeController {
private final LikeService likeService;
@PostMapping
public ResponseEntity<Response> like(Authentication authentication, @PathVariable Long postId){
String userName = authentication.getName();
LikeResponse likeResponse = likeService.like(userName,postId);
return ResponseEntity.ok().body(Response.of("SUCCESS",likeResponse));
}
}
LikeResponse
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
@Setter
public class LikeResponse {
private String result;
public static LikeResponse of(String result) {
return LikeResponse.builder()
.result(result)
.build();
}
}
좋아요 서비스 구현
LikeService
@Service
@RequiredArgsConstructor
public class LikeService {
private final LikeRepository likeRepository;
private final UserRepository userRepository;
private final PostRepository postRepository;
public LikeResponse like(String userName, Long postId) {
User findUser = AppUtil.findUser(userRepository,userName);
Post findPost = AppUtil.findPost(postRepository,postId);
Like like = Like.of(findUser,findPost);
likeRepository.save(like);
return LikeResponse.of("좋아요를 눌렀습니다.");
}
}
좋아요 리포지토리 구현
LikeRepository
public interface LikeRepository extends JpaRepository<Like,Long> {
}
Like
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
@Table(name = "likes")
@Getter
public class Like extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "userId")
private User user;
@ManyToOne
@JoinColumn(name = "postId")
private Post post;
public static Like of(User user, Post post){
return Like.builder()
.user(user)
.post(post)
.build();
}
}
🌉 회고
- 단순한 기능이라 구현하기는 쉬웠다.
- 하지만 좋아요를 두 번 누를 경우를 처리해야 한다.
- 두 번 누를 경우 좋아요가 취소되도록 처리하려고 한다.