// TemplateServiceTest
@DisplayName("템플릿 작성자는 템플릿을 삭제할 수 있다.")
@Test
void deleteTemplateTest() {
//given
var position = positionRepository.save(UserFixtures.createPosition());
var user = UserFixtures.createUser(position);
var savedUser = userRepository.save(user);
var template = createTemplate(savedUser);
var savedTemplate = templateRepository.save(template);
//when
templateService.deleteTemplate(createAuthContext(savedUser.getId()), savedTemplate.getId());
//then
assertThatThrownBy(() -> templateRepository.getById(savedTemplate.getId()))
.isInstanceOf(IllegalArgumentException.class);
}
//TemplateRepository
public interface TemplateRepository extends JpaRepository<Template, Long> {
Optional<Template> findById(Long templateId);
default Template getById(Long templateId) {
return findById(templateId)
.orElseThrow(IllegalArgumentException::new);
}
}

위에 테스트는 "템플릿 작성자는 템플릿을 삭제할 수 있어야 하며, 삭제한 템플릿은 더 이상 DB에서 조회되어서는 안된다" 라는 가설을 검증하는 테스트입니다. 그래서 없는 템플릿의 대한 조회를 하게되면 IllegalArgumentException 예외가 발생하는걸 예상 했으나 InvalidDataAccessApiUsageException예외가 발생하는걸 알 수 있습니다.
이유가 무엇일까요?
자세히 찾아보지는 못했지만 JpaRepository를 사용하게 되면 SimpleJpaRepository를 사용하게 되는데 이는 @Repository어노테이션을 사용하고 있습니다.
PersistenceExceptionTranslationPostProcessor 라는 빈을 통해 @Repository 어노테이션이 붙어 있는 모든 빈에 대해 예외 변환 어드바이스를 적용하고 예외가 발생하면 `EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible` 와 같은 메서드를 사용해서 예외를 스프링 스펙 예외로 변환합니다.
아래 보시면 IllegalArgumentException를 찾아서 InvalidDataAccessApiUsageException로 변환해 반환하고 있습니다. 현재는 큰 문제는 없지만 나중에 프로젝트가 커짐에 따라 커스텀 예외로 변환하면 문제가 해결 될 거 같습니다.
//EntityManagerFactoryUtils
public static DataAccessException convertJpaAccessExceptionIfPossible(RuntimeException ex) {
// Following the JPA specification, a persistence provider can also
// throw these two exceptions, besides PersistenceException.
if (ex instanceof IllegalStateException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof IllegalArgumentException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
// Check for well-known PersistenceException subclasses.
if (ex instanceof EntityNotFoundException entityNotFoundException) {
return new JpaObjectRetrievalFailureException(entityNotFoundException);
}
if (ex instanceof NoResultException) {
return new EmptyResultDataAccessException(ex.getMessage(), 1, ex);
}
if (ex instanceof NonUniqueResultException) {
return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex);
}
if (ex instanceof QueryTimeoutException) {
return new org.springframework.dao.QueryTimeoutException(ex.getMessage(), ex);
}
if (ex instanceof LockTimeoutException) {
return new CannotAcquireLockException(ex.getMessage(), ex);
}
if (ex instanceof PessimisticLockException) {
return new PessimisticLockingFailureException(ex.getMessage(), ex);
}
if (ex instanceof OptimisticLockException optimisticLockException) {
return new JpaOptimisticLockingFailureException(optimisticLockException);
}
if (ex instanceof EntityExistsException) {
return new DataIntegrityViolationException(ex.getMessage(), ex);
}
if (ex instanceof TransactionRequiredException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
// If we have another kind of PersistenceException, throw it.
if (ex instanceof PersistenceException) {
return new JpaSystemException(ex);
}
// If we get here, we have an exception that resulted from user code,
// rather than the persistence provider, so we return null to indicate
// that translation should not occur.
return null;
}
'BE > Spring' 카테고리의 다른 글
[JPA] LazyLoading could not initialize proxy - no Session 문제 해결하기 (1) | 2023.10.30 |
---|---|
@DataJpaTest에서 @Repository 사용하기 (1) | 2023.09.06 |
스프링부트에서 레디스 컨테이너 Connection refused 문제 해결 (0) | 2023.08.28 |
@SpringBootApplication 이란? (0) | 2023.08.10 |
스프링부트3 Spring REST docs + Swagger UI 사용하기 (0) | 2023.08.04 |