• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

테스트 시 DB 싱크 문제

21.04.14 09:38 작성 조회수 329

0

안녕하세요 기선님!

테스트코드를 작성하는 도중에, 태그를 추가하는 테스트와 태그를 삭제하는 테스트에서 NullPotintException이 발생했습니다. 

이유는 account 객체에서 getTags() 메서드를 호출한 결과가 Null이었기 때문이었습니다. 이 말은 ManyToMany 관계가 정상적으로 DB에 싱크가 되지 않았다는 것인데,

기선님 말씀대로 테스크 클래스에 @Transactional을 통해서  트랜잭션 처리를 해주었음에도 싱크가 이루어지지 않는 것 같습니다.

mockMvc.perform(post("/settings/tags/add")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(tagForm))
.with(csrf()))
.andExpect(status().isOk());

트랜잭션 처리를 해주어서 persist하게 만들어 줬는데도 왜 DB 싱크가 제대로 되지 않는 것인지 궁금합니다!!

그리고 테스트가 아닌 실제 어플리케이션 실행에서는 문제없이 잘 작동을 했습니다!

org.springframework.web.util.NestedServletException:

Request processing failed; nested exception is java.lang.NullPointerException: Cannot invoke "java.util.Set.add(Object)" because the return value of "com.sejin.domain.Account.getTags()" is null

답변 4

·

답변을 작성해보세요.

0

말씀하시는 "트랜잭션 처리"라고 언급하시는게 정확히 어떤 것일까요?

김세진님의 프로필

김세진

질문자

2021.04.15

accoutRepostitory를 통해 불러온 detached한 account 객체를 통해 트랜잭션 내부에서 새로운 persist한 account 객체를 생성하는 경우를 말했던 것이었습니다!

테스트 코드상에서는 SettingControllerTest 클래스에 @Transactional을 사용한 것을 의미했던 것인데, 제가 두서없이 말씀 드린 것 같네요..!  ㅎㅎ

애플리케이션을 실행할 때는 accountService 를 통해 트랜잭션 내부에서 잘 동작했는데, 테스트 코드상에서는 동일한 흐름으로 진행되는데 이러한 차이가 발생했던 것이 잘 이해가 안됐습니다!

이러한 차이는 "Account 클래스의 tags의 초깃값을 null 로 그대로 두었냐, 아니면 new HashSet<>(); 을 호출하여 임의의 컬렉션을 참조하게 하였냐" 입니다! 

0

김세진님의 프로필

김세진

질문자

2021.04.15

안녕하세요 기선님! 

계속 고민하고 이유를 찾다가 결국은 해결을 하게 됐습니다. 이해를 해서 해결한 것은 아니지만요..^^

제가 기존 Account 클래스의 tags 초기화 값을

Set<Tag> tags = new HashSet<>();

으로 초기화 해주지 않아 기본적으로  null 을 참조하고 있었습니다.

하지만 그래도 이해가 되지 않는 부분이 이전에 애플리케이션에서 실행할 당시, tags의 초깃값을 지정해주지 않아도 트랜잭션 처리를 해주면 DB와 잘 싱크가 되었는데, 테스트에서는 그것이 잘 적용이 안 되었습니다! 이러한 차이점은 어찌해서 발생하는지 궁금합니다..ㅎㅎ!

기본적으로 null을 참조하게 하는 것이 좋지 않은건 알고 있지만, 트랜잭션 처리가 되지 않았던 부분은 의문이네요! 

0

김세진님의 프로필

김세진

질문자

2021.04.14

안녕하세요 기선님!

기선님 말씀대로 디버거로 break 포인트들을 찍어서 확인해본 결과, 실제 애플리케이션 실행에서는 addTag 메소드에서 트랜잭션 내부에 있는 Optional 객체인 byId를 생성하고, 이에는 당연히 DB와 싱크된 tags 정보가 있었습니다!!

하지만 테스트 코드에서 생성된 Optional 객체인 byId에서는 트랜잭션 내부임에도 불구하고 tags 정보를 받아오지 못하여 그 인스턴스가 null인 것을 확인 할 수 있었습니다..!!

트랜잭션 내부에 있다고 생각이 되는데 왜 싱크가 잘 안된것인지 모르겠어서 다시 말씀드리게됐네요..!

비록 해결은 못했지만, 덕분에 디버거를 통해서 상태를 확인하는 방법에 대해서 학습을 할 수 있었습니다!^^

추가로 테스트 클래스에서 Transactional을 주지 않았을때에는 account에 tags 컬렉션에 예외를 발생시키지만

byId의 tags 필드는 또 DB와의 싱크가 되는 것인지, PersistentSet에 대한 정보가 있었습니다..!!

0

getTags()로 리턴 받은 Set<Tag>가 null 이라서 add를 호출하지 못하고 있는걸로 보이네요. 해당 tags 콜렉션을 초기화는 하셨나요? 디버거를 사용해서 왜 null인지 언제 해당 필드의 인스턴스를 만들기는 했는지 확인해 보셔야 겠습니다.