본문 바로가기
💻 뚝딱뚝딱/북북클럽

[개발일지#004] 팔로우 도메인 개발 및 테스트

by 뚜루리 2025. 1. 20.
728x90
320x100

[사용기술]

Java, Spring Boot, Spring JPA, MySQL

 

[만들려는 것]

책을 위한 SNS.

 

[오늘 하려는 것]

팔로우(Follow) 도메인 개발 및 테스트

 


 

 

TimelineRepository.java

package seulgi.bookbookclub.repository;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import seulgi.bookbookclub.domain.Follow;
import seulgi.bookbookclub.domain.Timeline;

import java.util.List;

@Repository
public class FollowRepository {

    @PersistenceContext
    private EntityManager em;

    //팔로우 추가
    public void save(Follow follow){
        em.persist(follow);
    }

    //팔로우 삭제 (언팔로우)
    public void delete(Follow follow){
        em.remove(follow);
    }

    // memberSeqs를 팔로잉한 회원 목록 조회
    public List<Follow> findFollowerByMember(Integer memberSeq){
        return em.createQuery("SELECT f FROM Follow f WHERE f.following.memberSeq = :memberSeq", Follow.class)
                .setParameter("memberSeq", memberSeq)
                .getResultList();
    }

    // memberSeqs가 팔로잉한 회원 목록 조회
    public List<Follow> findFollowingsByMember(Integer memberSeq) {
        return em.createQuery("SELECT f FROM Follow f WHERE f.follower.memberSeq = :memberSeq", Follow.class)
                .setParameter("memberSeq", memberSeq)
                .getResultList();
    }

    // 팔로우 존재 여부 확인
    public Follow findFollow(Integer followerSeq, Integer followingSeq) {
        return em.createQuery("SELECT f FROM Follow f WHERE f.follower.memberSeq = :followerSeq AND f.following.memberSeq = :followingSeq", Follow.class)
                .setParameter("followerSeq", followerSeq)
                .setParameter("followingSeq", followingSeq)
                .getResultStream()
                .findFirst()
                .orElse(null);
    }
}
  • 팔로우삭제 즉, 언팔로우는 물리삭제로 진행해보기로 함.
  • findFollowingByMember() : 한 회원을 팔로잉을 한 회원 리스트를 조회
  • findFollowingsByMember() : 한 회원이 팔로잉한 회원 리스트를 조회
  • findFollow() : 팔로잉을 중복으로 불가 하기 때문에 팔로잉 여부를 조회

 

 

FollowSerivce.java

package seulgi.bookbookclub.service;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import seulgi.bookbookclub.domain.Follow;
import seulgi.bookbookclub.domain.Member;
import seulgi.bookbookclub.repository.FollowRepository;

import java.util.List;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class FollowService {

    private final FollowRepository followRepository;

    //팔로우 추가
    @Transactional
    public void follow(Member follower, Member following) {
        //이미 팔로우 중인지 확인
        Follow existingFollow = followRepository.findFollow(follower.getMemberSeq(), following.getMemberSeq());
        if (existingFollow != null) {
            throw new IllegalStateException("이미 팔로우 중입니다.");
        }
        Follow follow = new Follow(follower, following);
        followRepository.save(follow);
    }

    //언팔로우
    @Transactional
    public void unfollow(Member follower, Member following){
        //이미 팔로우 중인지 확인
        Follow existingFollow = followRepository.findFollow(follower.getMemberSeq(), following.getMemberSeq());
        if (existingFollow == null){
            throw new IllegalStateException("팔로우 관계가 존재하지 않습니다.");
        }
        followRepository.delete(existingFollow);
    }

    // memberSeqs를 팔로잉한 회원 목록 조회
    public List<Follow> getFollowers(Integer memberSeq) {
        return followRepository.findFollowerByMember(memberSeq);
    }

    // memberSeqs가 팔로잉한 회원 목록 조회
    public List<Follow> getFollowings(Integer memberSeq) {
        return followRepository.findFollowingsByMember(memberSeq);
    }
}

 

 

팔로우 도메인 테스트

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.Follow;
import seulgi.bookbookclub.domain.Member;
import seulgi.bookbookclub.repository.FollowRepository;
import seulgi.bookbookclub.repository.MemberRepository;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Transactional
class FollowServiceTest {
    
    @Autowired FollowService followService;
    @Autowired MemberRepository memberRepository;
    @Autowired FollowRepository followRepository;

    @Test
    void 팔로우추가() {
        // given
        Member follower = new Member("followerId", "1234", "팔로워");
        Member following = new Member("followingId", "5678", "팔로잉");

        memberRepository.save(follower);
        memberRepository.save(following);

        // when
        followService.follow(follower, following);

        // then
        List<Follow> follows = followRepository.findFollowingsByMember(follower.getMemberSeq());
        assertEquals(1, follows.size());
        assertEquals(following.getMemberSeq(), follows.get(0).getFollowing().getMemberSeq());
    }

    @Test
    void 팔로우중복방지() {
        // given
        Member follower = new Member("followerId", "1234", "팔로워");
        Member following = new Member("followingId", "5678", "팔로잉");

        memberRepository.save(follower);
        memberRepository.save(following);
        followService.follow(follower, following);

        // when & then
        IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
            followService.follow(follower, following);
        });
        assertEquals("이미 팔로우 중입니다.", exception.getMessage());
    }

    @Test
    void 언팔로우() {
        // given
        Member follower = new Member("followerId", "1234", "팔로워");
        Member following = new Member("followingId", "5678", "팔로잉");

        memberRepository.save(follower);
        memberRepository.save(following);
        followService.follow(follower, following);

        // when
        followService.unfollow(follower, following);

        // then
        List<Follow> follows = followRepository.findFollowingsByMember(follower.getMemberSeq());
        assertTrue(follows.isEmpty());
    }

    @Test
    void 팔로잉을한_목록조회() {
        // given
        Member follower = new Member("followerId", "1234", "팔로워");
        Member following1 = new Member("following1Id", "5678", "팔로잉1");
        Member following2 = new Member("following2Id", "91011", "팔로잉2");

        memberRepository.save(follower);
        memberRepository.save(following1);
        memberRepository.save(following2);

        followService.follow(follower, following1);
        followService.follow(follower, following2);

        // when
        //follower를 팔로잉한 회원 목록 조회
        List<Follow> follows = followService.getFollowings(follower.getMemberSeq());

        // then
        assertEquals(2, follows.size());
        assertEquals(following1.getMemberSeq(), follows.get(0).getFollowing().getMemberSeq());
        assertEquals(following2.getMemberSeq(), follows.get(1).getFollowing().getMemberSeq());
    }

    @Test
    void 팔로잉을당한_목록조회() {
        // given
        Member following = new Member("followingId", "5678", "팔로잉");
        Member follower1 = new Member("follower1Id", "1234", "팔로워1");
        Member follower2 = new Member("follower2Id", "91011", "팔로워2");

        memberRepository.save(following);
        memberRepository.save(follower1);
        memberRepository.save(follower2);

        followService.follow(follower1, following);
        followService.follow(follower2, following);

        // when
        //following가 팔로잉한
        List<Follow> followers = followService.getFollowers(following.getMemberSeq());

        // then
        assertEquals(2, followers.size());
        assertEquals(follower1.getMemberSeq(), followers.get(0).getFollower().getMemberSeq());
        assertEquals(follower2.getMemberSeq(), followers.get(1).getFollower().getMemberSeq());
    }

}

 

테스트 성공

(아니 나 팔로우, 팔로잉 이거 나조차도 너무 헷갈려서 테스트 코드만 한나절 짜고, 서비스랑 레파지토리도 수십번 변경한 듯....)

728x90
320x100