728x90
320x100
[사용기술]
Java, Spring Boot, Spring JPA, MySQL
[만들려는 것]
책을 위한 SNS.
[오늘 하려는 것]
좋아요(Likes) 도메인 개발 및 테스트
LikesRepository.java
package seulgi.bookbookclub.repository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import seulgi.bookbookclub.domain.Likes;
import java.util.Optional;
@Repository
public class LikesRepository {
@PersistenceContext
private EntityManager em;
//좋아요 추가
public void save(Likes likes){
em.persist(likes);
}
//좋아요 해제
public void delete(Likes likes){
em.remove(likes);
}
// 한 회원이 특정 타임라인에 좋아요 눌렀는지 조회
public Optional<Likes> findLike(Integer memberSeq, Integer timelineSeq) {
return em.createQuery("SELECT l FROM Likes l WHERE l.member.memberSeq = :memberSeq AND l.timeline.timelineSeq = :timelineSeq", Likes.class)
.setParameter("memberSeq", memberSeq)
.setParameter("timelineSeq", timelineSeq)
.getResultStream()
.findFirst();
}
// 특정 타임라인의 좋아요 개수 조회
public Long countLikesByTimeline(Integer timelineSeq) {
return em.createQuery("SELECT COUNT(l) FROM Likes l WHERE l.timeline.timelineSeq = :timelineSeq", Long.class)
.setParameter("timelineSeq", timelineSeq)
.getSingleResult();
}
}
- 좋아요를 추가하고 삭제하는 간단한 로직과 좋아요는 중복 좋아요가 불가능하므로 중복 좋아요를 확인할 수 있는 로직, 그리고 특정 타임라인의 좋아요 갯수를 조회 하는 로직을 만듦.
LikesService.java
package seulgi.bookbookclub.service;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import seulgi.bookbookclub.domain.Likes;
import seulgi.bookbookclub.domain.Member;
import seulgi.bookbookclub.domain.Timeline;
import seulgi.bookbookclub.repository.LikesRepository;
import seulgi.bookbookclub.repository.MemberRepository;
import seulgi.bookbookclub.repository.TimelineRepository;
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class LikesService {
private final LikesRepository likesRepository;
private final MemberRepository memberRepository;
private final TimelineRepository timelineRepository;
// 좋아요 추가
@Transactional
public void addLike(Integer memberSeq, Integer timelineSeq) {
Member member = memberRepository.findByMemberSeq(memberSeq);
Timeline timeline = timelineRepository.findById(timelineSeq);
likesRepository.findLike(memberSeq, timelineSeq).ifPresent(like -> {
throw new IllegalStateException("이미 좋아요를 눌렀습니다.");
});
Likes like = new Likes(member, timeline);
likesRepository.save(like);
}
// 좋아요 취소
@Transactional
public void removeLike(Integer memberSeq, Integer timelineSeq) {
Likes like = likesRepository.findLike(memberSeq, timelineSeq)
.orElseThrow(() -> new IllegalArgumentException("좋아요가 존재하지 않습니다."));
likesRepository.delete(like);
}
// 특정 타임라인의 좋아요 개수 조회
public Long countLikes(Integer timelineSeq) {
return likesRepository.countLikesByTimeline(timelineSeq);
}
}
- 중복 좋아요가 불가능 함으로 ifPresent()을 사용해서 중복 좋아요 시에 예외 처리를 진행.
- 좋아요 취소는 좋아요를 이미 누른 상태일 때만 가능하므로 orElseThrow()을 사용해서 좋아요를 누르지 않았는데 좋아요를 취소했을 때 예외 처리 진행.
- ifPresent(): 값이 있으면 작업 실행, 없으면 무시.
- orElseThrow(): 값이 있으면 반환, 없으면 예외 발생.
좋아요 도메인 테스트
package seulgi.bookbookclub.service;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import seulgi.bookbookclub.domain.Book;
import seulgi.bookbookclub.domain.Member;
import seulgi.bookbookclub.domain.Timeline;
import seulgi.bookbookclub.repository.BookRepository;
import seulgi.bookbookclub.repository.MemberRepository;
import seulgi.bookbookclub.repository.TimelineRepository;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
@Transactional
class LikesServiceTest {
@Autowired private LikesService likesService;
@Autowired private MemberRepository memberRepository;
@Autowired private TimelineRepository timelineRepository;
@Autowired private BookRepository bookRepository;
@Test
void 좋아요추가() {
// given
Member member = new Member("testMember", "1234", "닉네임");
memberRepository.save(member);
Book book = new Book("12345678910", "책제목", "글쓴이", "출판사");
bookRepository.save(book);
Timeline timeline = new Timeline(member, "테스트 글 내용", book);
timelineRepository.save(timeline);
// when
likesService.addLike(member.getMemberSeq(), timeline.getTimelineSeq());
// then
Long likeCount = likesService.countLikes(timeline.getTimelineSeq());
assertEquals(1, likeCount);
}
@Test
void 좋아요중복방지() {
// given
Member member = new Member("testMember", "1234", "닉네임");
memberRepository.save(member);
Book book = new Book("12345678910", "책제목", "글쓴이", "출판사");
bookRepository.save(book);
Timeline timeline = new Timeline(member, "테스트 글 내용", book);
timelineRepository.save(timeline);
likesService.addLike(member.getMemberSeq(), timeline.getTimelineSeq());
// when & then
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
likesService.addLike(member.getMemberSeq(), timeline.getTimelineSeq());
});
assertEquals("이미 좋아요를 눌렀습니다.", exception.getMessage());
}
@Test
void 좋아요취소() {
// given
Member member = new Member("testMember", "1234", "닉네임");
memberRepository.save(member);
Book book = new Book("12345678910", "책제목", "글쓴이", "출판사");
bookRepository.save(book);
Timeline timeline = new Timeline(member, "테스트 글 내용", book);
timelineRepository.save(timeline);
likesService.addLike(member.getMemberSeq(), timeline.getTimelineSeq());
// when
likesService.removeLike(member.getMemberSeq(), timeline.getTimelineSeq());
// then
Long likeCount = likesService.countLikes(timeline.getTimelineSeq());
assertEquals(0, likeCount);
}
}
테스트 성공
728x90
320x100
'💻 뚝딱뚝딱 > 북북클럽' 카테고리의 다른 글
[개발일지#007] 회원 등록/수정/조회 API 개발 (0) | 2025.01.21 |
---|---|
[개발일지#006] 조회용 샘플데이터 생성 (0) | 2025.01.21 |
[개발일지#004] 팔로우 도메인 개발 및 테스트 (0) | 2025.01.20 |
[개발일지#003] 타임라인 도메인 개발 및 테스트 (0) | 2025.01.20 |
[개발일지#002] 회원 도메인 개발 및 테스트 (0) | 2025.01.16 |