이어서, 질문 데이터를 수정하는 테스트 코드를 작성해보자.
assertTrue(값)은 값이 true인지를 테스트한다.
질문 데이터를 조회한 다음 subject를 "수정된 제목" 이라는 값으로 수정했다. 변경된 Question 데이터를 저장하기 위해서는 this.questionRepository.save(q) 처럼 리포지터리의 save 메서드를 사용한다.
테스트를 수행해 보면 콘솔 로그에서 다음과 같은 update 문이 실행되었음을 확인할 수 있을 것이다.
데이터 삭제하기
이어서 데이터를 삭제하는 것도 실습해 보자. 여기서는 첫 번째 질문을 삭제해 보자.
리포지터리의 count() 메서드는 해당 리포지터리의 총 데이터건수를 리턴한다.
Question 리포지터리의 delete 메서드를 사용하여 데이터를 삭제했다. 삭제하기 전에는 데이터 건수가 2, 삭제한 후에는 데이터 건수가 1인지를 테스트했다. 테스트는 잘 통과될 것이다.
답변 데이터 생성 후 저장하기
이번에는 답변(Answer) 데이터를 생성하고 저장해 보자.
답변 데이터 처리를 위해서는 답변 리포지터리가 필요하므로 AnswerRepository 객체를 @Autowired로 주입했다. 답변 데이터를 생성하려면 질문 데이터가 필요하므로 우선 질문 데이터를 구해야 한다. id가 2인 질문 데이터를 가져온 다음 Answer 엔티티의 question 속성에 방금 가져온 질문 데이터를 대입해(a.setQuestion(q)) 답변 데이터를 생성했다. Answer 엔티티에는 어떤 질문에 해당하는 답변인지 연결할 목적으로 question 속성이 필요하다.
테스트를 수행해 보자. 답변 데이터가 잘 생성될 것이다.
답변 조회하기
Answer도 Question 엔티티와 마찬가지로 id 속성이 기본 키이므로 값이 자동으로 생성된다. 다음처럼 id 값을 이용해 데이터를 조회해 보자.
id 값이 1인 답변을 조회했다. 그리고 그 답변의 질문 id가 2인지도 테스트해 보았다.
답변에 연결된 질문 찾기 vs 질문에 달린 답변 찾기
앞에서 구성한 Answer 엔티티의 question 속성을 이용하면 "답변에 연결된 질문"을 조회할 수 있다.
a.getQuestion()
답변에 연결된 질문 찾기는 Answer 엔티티에 question 속성이 정의되어 있어서 매우 쉽다. 그런데 반대의 경우도 가능할까? 즉, 질문에서 답변을 찾을수 있을까?
다음과 같이 질문 엔티티에 정의한 answerList를 사용하면 역시 쉽게 구할수 있다.
질문 객체로부터 답변 리스트를 구하는 테스트코드이다.
id가 2인 질문에 답변을 한 개 등록했으므로 위와 같이 검증할 수 있다. 하지만...
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mysite.sbb.Question.answerList, could not initialize proxy - no Session
(... 생략 ...)
오류가 뜬다. 난 처음에 빨간 줄 쳐진 answerList.get 때문에 오류가 난 줄 알았는데 아니었다.
원인은 Question 리포지터리가 findById를 호출하여 Question 객체를 조회하고 나면 DB세션이 끊어지기 때문이다. 그 이후에 실행되는 q.getAnswerList() 메서드는 세션이 종료되어 오류가 발생한다. 답변 데이터 리스트는 q 객체를 조회할때 가져오지 않고 q.getAnswerList() 메서드를 호출하는 시점에 가져오기 때문이다.
이렇게 필요한 시점에 데이터를 가져오는 방식을 Lazy 방식이라고 한다. 이와 반대로 q 객체를 조회할때 답변 리스트를 모두 가져오는 방식은 Eager 방식이라고 한다. @OneToMany, @ManyToOne 애너테이션의 옵션으로 fetch=FetchType.LAZY 또는 fetch=FetchType.EAGER 처럼 가져오는 방식을 설정할 수 있는데 이 책에서는 따로 지정하지 않고 항상 디폴트 값을 사용할 것이다.
사실 이 문제는 테스트 코드에서만 발생한다. 실제 서버에서 JPA 프로그램들을 실행할 때는 DB 세션이 종료되지 않기 때문에 위와 같은 오류가 발생하지 않는다. 테스트 코드를 수행할 때 위와 같은 오류를 방지할 수 있는 가장 간단한 방법은 다음처럼 @Transactional 애너테이션을 사용하는 것이다. @Transactional 애너테이션을 사용하면 메서드가 종료될 때까지 DB 세션이 유지된다.
따라서, 테스트 한정 코드를 다음과 같이 수정한다.
그리고 실행을 해 보면..
문제없이 잘 실행된다!
'백엔드 > Springboot' 카테고리의 다른 글
질문 목록과 템플릿(1) (0) | 2023.11.09 |
---|---|
<번외> 프로젝트 github 등록 삽질기 (2) | 2023.11.09 |
리포지터리(Repository) -2- (0) | 2023.09.18 |
리포지터리(Repository) -1- (0) | 2023.09.18 |
엔티티(Entity) -2- (0) | 2023.09.17 |