@BeforeEach 사용할 때 트랜젝션 사이클 문의
미해결
스프링 DB 2편 - 데이터 접근 활용 기술
안녕하세요! 테스트 케이스에 @BeforeEach로 데이터 삽입 후 처리하는 중 오류가 발생해서 문의 드립니다. 해당 오류 : java.util.NoSuchElementException: No value present 통합 테스트에서만 발생하고 개별로 메소드마다 돌리면 문제 없음. 제가 이해하기론 Test class에 @Transactional을 붙여주고 돌리면 테스트 메소드 1개 실행 후 정상 처리되면 롤백. 이렇게 이해하고 있습니다. 그래서 제 테스트가 돌아가는 사이클을 @BeforeEach - > 좋아요_개수 Test -> 정상 처리 롤백 @BeforeEach - > 좋아요_여부 Test -> 정상 처리 롤백 @BeforeEach - > 좋아요_체크 Test -> 정상 처리 롤백 @BeforeEach - > 좋아요_해제 Test -> 정상 처리 롤백 위와 같이 이해하고 테스트들마다 정상 처리 롤백 후 비어있는 데이터에 다시 @BeforeEach로 데이터를 넣어주기에 넣어주는 데이터들의 ID값(GeneratedValue)이 1부터 시작하는 걸로 이해했습니다. 그런데 등록된 데이터의 ID값으로 findOne을 하니 해당 ID가 없다고 뜹니다. 무슨 문제인가..하고 디버깅을 돌리니 1번 좋아요_개수 테스트의 business ID = 1번, 2번 2번 좋아요_여부 테스트의 business ID = 3번, 4번 3번 좋아요_체크 테스트의 business ID = 5번, 6번 4번 좋아요_해제 테스트의 business ID = 7번, 8번 이렇게 ID값이 부여가 됩니다. 롤백 자체가 되지 않았다면 1번을 조회했을 때도 데이터는 나와야 하는데 그건 나오지 않고 ID값만 다음 숫자로 넘어가는데 제가 무언가 놓치고 있을까요? 선생님의 강의는 전부 결제해서 트랜젝션 관련 부분을 아무리 들어봐도 아직 미숙해서 그런지 해당 부분의 문제를 모르겠습니다.. 클래스 레벨에 @Transactional을 붙여주면 내부에 before() 메소드 안에 트랜젝션들도 전파되고, 정상 처리되는 로직이라면 데이터 등록 후 좋아요_ㅁㅁ Test 로 넘어가고, 그 안에도 정상처리 되면 클래스 레벨에 물리 트랜젝션 커밋 처리 후 다음 테스트 로직이 실행 되는 걸로 이해 했는데 잘못 이해했다면 말씀 부탁드립니다ㅠ.ㅠ BusinessMarkServiceTest @SpringBootTest @Transactional public class BusinessMarkServiceTest { @Autowired BusinessMarkService businessMarkService; @Autowired MemberService memberService; @Autowired BusinessService businessService; @Autowired LoginService loginService; @BeforeEach public void before() { Member member = new Member(); member.setNickname("testMember"); member.setMail("testMember@test.com"); member.setPassword("test1234!"); member.setMember_type("B"); member.setMember_status("J"); member.setHint_password("hint_01"); member.setAnswer_password("answer"); member.setUpdated_at(now()); member.setCreated_at(now()); memberService.join(member); Member member2 = new Member(); member2.setNickname("testMember2"); member2.setMail("testMember2@test.com"); member2.setPassword("test1234!"); member2.setMember_type("B"); member2.setMember_status("J"); member2.setHint_password("hint_01"); member2.setAnswer_password("answer"); member2.setUpdated_at(now()); member2.setCreated_at(now()); memberService.join(member2); Business business = new Business(); business.setBusinessName("테스트밥집"); business.setHomepage("test.com"); business.setPhone("010-1234-5678"); business.setAddress("제주특별자치도 제주시 첨단로 242"); business.setLng((float) 33.450701); business.setLat((float) 126.570667); business.setCreated_at(now()); business.setUpdated_at(now()); businessService.join(business); Business business2 = new Business(); business2.setBusinessName("테스트밥집2"); business2.setHomepage("test2.com"); business2.setPhone("010-1234-5678"); business2.setAddress("제주특별자치도 제주시 첨단로 242"); business2.setLng((float) 33.450701); business2.setLat((float) 126.570667); business2.setCreated_at(now()); business2.setUpdated_at(now()); businessService.join(business2); } @Test public void 좋아요_체크() throws Exception{ //given Member loginMember = loginService.login("testMember2@test.com", "test1234!"); Business findBusiness = businessService.findOne(1L); //when BusinessMarkDto businessMarkDto = new BusinessMarkDto(loginMember,findBusiness.getId()); businessMarkService.pushBusinessMark(businessMarkDto); //then assertEquals(1, businessMarkService.getBusinessLikeInfo(businessMarkDto).getBusinessLikeNum()); } @Test public void 좋아요_해제() throws Exception{ //given Member loginMember = loginService.login("testMember@test.com", "test1234!"); Member loginMember2 = loginService.login("testMember2@test.com", "test1234!"); Business findBusiness = businessService.findOne(1L); //좋아요 표시하기 BusinessMarkDto businessMarkDto = new BusinessMarkDto(loginMember,findBusiness.getId()); businessMarkService.pushBusinessMark(businessMarkDto); BusinessMarkDto businessMarkDto2 = new BusinessMarkDto(loginMember2,findBusiness.getId()); businessMarkService.pushBusinessMark(businessMarkDto2); //when //businessMarkDto2가 한번 더 좋아요 눌러서 해제 시키기 businessMarkService.pushBusinessMark(businessMarkDto2); //then assertEquals(1, businessMarkService.getBusinessLikeInfo(businessMarkDto).getBusinessLikeNum()); } @Test public void 좋아요_개수() throws Exception{ //given Member loginMember = loginService.login("testMember@test.com", "test1234!"); Member loginMember2 = loginService.login("testMember2@test.com", "test1234!"); Business findBusiness = businessService.findOne(1L); //좋아요 표시하기 BusinessMarkDto businessMarkDto = new BusinessMarkDto(loginMember,findBusiness.getId()); businessMarkService.pushBusinessMark(businessMarkDto); BusinessMarkDto businessMarkDto2 = new BusinessMarkDto(loginMember2,findBusiness.getId()); businessMarkService.pushBusinessMark(businessMarkDto2); //when long businessMarkNum = businessMarkService.getBusinessLikeInfo(businessMarkDto2).getBusinessLikeNum(); //then assertEquals(2, businessMarkNum); } @Test public void 좋아요_여부() throws Exception{ //given Member loginMember = loginService.login("testMember@test.com", "test1234!"); Business findBusiness = businessService.findOne(1L); //when BusinessMarkDto businessMarkDto = new BusinessMarkDto(loginMember,findBusiness.getId()); businessMarkService.pushBusinessMark(businessMarkDto); Boolean check = businessMarkService.getBusinessLikeInfo(businessMarkDto).getCheck(); //then assertEquals(true, check); } } BusinessMarkService @Slf4j @Service @Transactional @RequiredArgsConstructor public class BusinessMarkService { private final BusinessMarkRepository businessMarkRepository; private final BusinessRepository businessRepository; //좋아요 및 취소 public Boolean pushBusinessMark(BusinessMarkDto businessMarkDto) { businessMarkRepository.BusinessMarkSearch(businessMarkDto.getMember().getMail(), businessMarkDto.getBusinessId()) .ifPresentOrElse(businessMark -> businessMarkRepository.deleteById(businessMark.getId()), ()-> { Business business = getBusiness(businessMarkDto); businessMarkRepository.save(new BusinessMark(businessMarkDto.getMember(), business)); }); return true; } //업체 게시글 찾기 @Transactional(readOnly = true) public Business getBusiness(BusinessMarkDto businessMarkDto) { return businessRepository.findById(businessMarkDto.getBusinessId()) .orElseThrow(() -> new IllegalArgumentException("해당 게시글은 존재하지 않습니다.")); } // 좋아요 개수 @Transactional(readOnly = true) public BusinessMarkResponseDto getBusinessLikeInfo(BusinessMarkDto businessMarkDto) { long businessLikeNum = getBusinessLikeNum(businessMarkDto); boolean check = checkPushedLike(businessMarkDto); return new BusinessMarkResponseDto(businessLikeNum, check); } @Transactional(readOnly = true) public Boolean checkPushedLike(BusinessMarkDto businessMarkDto) { return businessMarkRepository.BusinessMarkSearch(businessMarkDto.getMember().getMail(), businessMarkDto.getBusinessId()) .isPresent(); /*Optional<BusinessMark> businessMark = businessMarkRepository.BusinessMarkSearch(businessMarkDto.getMember().getMail(), businessMarkDto.getBusinessId()); if(businessMark != null){ return true; } return false;*/ } @Transactional(readOnly = true) public long getBusinessLikeNum(BusinessMarkDto businessMarkDto) { return businessMarkRepository.BusinessMark(businessMarkDto.getBusinessId()); } } MemberService @Slf4j @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class MemberService { @Autowired private final MemberRepository memberRepository; @Autowired private PasswordEncoder passwordEncoder; /** 회원가입 **/ @Transactional public String join(Member member){ //비밀번호 암호화 후 레포지토리에 넘기기 String encodedPassword = passwordEncoder.encode(member.getPassword()); member.setPassword(encodedPassword); validateDuplicateMember(member);//중복회원검증 memberRepository.save(member); return member.getMail(); } /** 중복회원검증 **/ private void validateDuplicateMember(Member member) { List<Member> findMembers = memberRepository.findByMail(member.getMail()); if (!findMembers.isEmpty()){ throw new IllegalStateException("이미 존재하는 회원입니다"); } } private void validateDuplicateNickname(Member member) { Member findMembers = memberRepository.findOndByMail(member.getMail()); if (!findMembers.getNickname().equals(member.getNickname())){ throw new IllegalStateException("이미 존재하는 회원입니다"); } } /** 회원전체조회 **/ public List<Member> findMembers(){ return memberRepository.findAll(); } public Member findOne(String mail) { return memberRepository.findOndByMail(mail); } /** 회원 수정 **/ @Transactional public void update(String mail, String nickname, String answer_password){ Member member = memberRepository.findOndByMail(mail); if(nickname.equals(member.getNickname())) { validateDuplicateNickname(member); } member.setNickname(nickname); member.setAnswer_password(answer_password); member.setUpdated_at(now()); } /** 회원 탈퇴 **/ @Transactional public String delete(String mail, String password){ Member findUser = memberRepository.findOndByMail(mail); if(!passwordEncoder.matches(password,findUser.getPassword())){ //throw new IllegalStateException("비밀번호가 맞지 않습니다."); System.out.println("암호 실패"); return null; } findUser.setUpdated_at(now()); findUser.setMember_status("D"); return findUser.getPassword(); } } BusinessService @Slf4j @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class BusinessService { @Autowired private final BusinessRepository businessRepository; @Autowired private final MemberRepository memberRepository; @Autowired private PasswordEncoder passwordEncoder; /** 중복업체검증 **/ private void validateDuplicateBusiness(Business business) { List<Business> findBusiness = businessRepository.findByBusinessName(business.getBusinessName()); if (!findBusiness.isEmpty()){ throw new IllegalStateException("이미 존재하는 업체명입니다"); } } /** 업체생성 **/ @Transactional public String join(Business business){ validateDuplicateBusiness(business);//중복회원검증 log.info("business {}", business); businessRepository.save(business); return business.getBusinessName(); } /** 업체 수정 **/ /** @Transactional public void saveBusiness(Business business){ businessRepository.save(business); } **/ @Transactional public void update(Long id, String BusinessName, String homepage, String phone, String address, float lat, float lng, String etc){ Business business = businessRepository.findById(id).orElseThrow(); if(!BusinessName.equals(business.getBusinessName())) { validateDuplicateBusiness(business); //중복 업체명 검증 } business.setBusinessName(BusinessName); business.setHomepage(homepage); business.setPhone(phone); business.setAddress(address); business.setLat(lat); business.setLng(lng); business.setEtc(etc); business.setUpdated_at(now()); } /** 업체 삭제 **/ @Transactional public String delete(Member member, Long id){ Member findUser = memberRepository.findOndByMail(member.getMail()); //Business business = businessRepository.findById(id).get(); Business business = businessRepository.findById(id).orElseThrow(); if(!passwordEncoder.matches(member.getPassword(),findUser.getPassword())){ //throw new IllegalStateException("비밀번호가 맞지 않습니다."); System.out.println("암호 실패"); return null; } business.setStatus("D"); business.setUpdated_at(now()); return findUser.getPassword(); } /** 업체 찾기 **/ public Business findOne(Long id) { Business business = businessRepository.findById(id).orElseThrow(); return business; } } LoginService @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class LoginService { @Autowired private final MemberRepository memberRepository; @Autowired private PasswordEncoder passwordEncoder; public Member findOne(String mail){ return memberRepository.findOndByMail(mail);} /** 로그인 **/ @Transactional //public String login(Member member){ public Member login(String mail, String password){ List<Member> findMember = memberRepository.findByMail(mail); Member findUser = memberRepository.findOndByMail(mail); if (findMember==null){ //throw new IllegalStateException("해당 이메일의 유저가 존재하지 않습니다."); //System.out.println("이메일 실패"); return null; } if(!passwordEncoder.matches(password,findUser.getPassword())){ //throw new IllegalStateException("비밀번호가 맞지 않습니다."); return null; } System.out.println("로그인 완료 :"+findUser.getNickname()); //세션 표시를 위해 닉네임값 넘기기 return findUser; } /** 비밀번호 매치 **/ @Transactional public String passwordMatches(Member member){ Member findUser = memberRepository.findOndByMail(member.getMail()); if(!passwordEncoder.matches(member.getPassword(),findUser.getPassword())){ //throw new IllegalStateException("비밀번호가 맞지 않습니다."); System.out.println("암호 실패"); return null; } return findUser.getPassword(); } /** 비밀번호 변경 **/ @Transactional public void updatePassword(String mail, String editPassword){ Member member = memberRepository.findOndByMail(mail); if (editPassword.equals(member.getPassword())) { throw new IllegalStateException("이전 비밀번호와 동일합니다."); } member.setPassword(editPassword); member.setUpdated_at(now()); } }
- spring





