개발환경

  • MacBook Air (M1, 2020)
  • OpenJDK 11
  • IntelliJ IDEA Community Edition
  • Spring Boot 2.7.3(예정)
  • MySQL Workbench 8.0.28


기간

  • 2022.8.15 ~


주제

  • 오늘의 소비에 대한 기억과 감정을 기록으로 남기고 나중에 되돌아보는 시간이 있었으면 좋겠다는 생각에 진행하게 된 프로젝트이다.
  • 새로 산 물건의 사진을 찍고 그에 대한 감상을 함께 글로 남길 수 있는 기능을 메인으로 제작할 것이다.


진행상황

  • 모~든 비즈니스의 시작, 회원 엔티티를 만들었다.

MemberRepository

@Repository
@RequiredArgsConstructor
public class MemberRepository {

    private final EntityManager em; // 의존성 자동 주입

    public Long save(Member member) {
        em.persist(member);
        return member.getId();
    }

    public List<Member> findAll() {
        return em.createQuery("select m from Member m", Member.class)
                .getResultList();
    }

    public Member findOne(Long id) {
        return em.find(Member.class, id);
    }

    public List<Member> findByName(String name) {
        return em.createQuery("select m from Member m where m.name = :name", Member.class)
                .setParameter("name", name)
                .getResultList();
    }
}
  • 회원 가입 기능과 조회 기능만 만들었다.

MemberService

  • RepositoryController 계층 사이에서 동작을 수행할 Service 계층을 만들었다.
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {

    private final MemberRepository memberRepository;

    /**
     * 회원 등록
     * 중복 회원 검사 후 통과하면 다음 트랜잭션 진행
     * @param member
     * @return member_id
     */
    @Transactional
    public Long join(Member member) {
        validateDuplicatedMember(member);
        memberRepository.save(member);
        return member.getId();
    }

    /**
     * 중복 회원 검사
     * @param member
     */
    private void validateDuplicatedMember(Member member) {
        List<Member> findMembers = memberRepository.findByName(member.getName());
        if (!findMembers.isEmpty()) {
            // username이 같은 회원이 존재하면 예외 발생
            throw new IllegalStateException("이미 존재하는 회원입니다.");
        }
    }

    /**
     * id로 회원 한 명 조회
     * @param id
     * @return member_id
     */
    public Member findMember(Long id) {
        return memberRepository.findOne(id);
    }

    /**
     * name으로 회원 한 명 조회
     * @param name
     * @return List<Member>
     */
    public List<Member> findByName(String name) {
        return memberRepository.findByName(name);
    }

    /**
     * 회원 전체 조회
     * @return List<Member>
     */
    public List<Member> findMembers() {
        return memberRepository.findAll();
    }
}
  • 다른 사람이 봤을 때 알아보기 쉽게 각 메서드에 대한 설명도 추가해 보았다. 뭔가 잘 정리된 느낌이라 좀 뿌듯하다.

회원 엔티티 테스트

  • 다 만들었으니까 동작을 잘 하는지 테스트를 해 보았다.
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Transactional
class MemberServiceTest {

    @Autowired
    MemberService memberService;
    @Autowired
    MemberRepository memberRepository;

    @Test
    public void 회원가입() throws Exception {
        // given
        Member member = new Member("memberC");

        // when
        Long savedId = memberService.join(member);

        // then
        assertEquals(member, memberRepository.findOne(savedId)); // 결과 OK!
    }

    @Test
    public void 중복회원검증() throws Exception {
        // given
        Member member = new Member("memberB");
        Member member1 = new Member("memberB");

        // when
        memberService.join(member);
        try {
            memberService.join(member1); // 예외 발생해야 함
        } catch (IllegalStateException e) {
            return; // 결과 OK!
        }

        // then
        fail("예외 발생해야 함");
    }
}
  • JUit5를 사용했다.
  • 그동안 예외를 직접 정의하고 던지는 코드를 작성해 본 경험이 많이 없어서 새롭고 재밌었다. 처음에는 잘 몰라서 중복 회원이 있을 경우 예외를 던지는 메서드(validateDuplicatedMember(member))MemberRepository 클래스에 작성했다가 계속 테스트 통과가 안 되어서 헤멨었다. 왜냐면 다른 종류의 예외가 먼저 터지는 바람에 사용자 정의한 예외까지 오지 않았기 때문인데… 그래서 테스트 코드의 catch에 걸리지 않아서 계속 테스트가 실패했던 것 같다. 검증 메서드를 MemberService로 옮겨준 다음 테스트를 통과할 수 있었다.


참고