인프런 커뮤니티 질문&답변

구준형님의 프로필 이미지

작성한 질문수

Practical Testing: 실용적인 테스트 가이드

개인적으로 궁금해서 질문드려요!

작성

·

80

0

저번에 OrderService 작성 시, LocalDateTime.now()를 사용하는걸 보고나서 강의대로 따라 안하고 인터페이스로 한 번 감싸서, 테스트코드에서는 고정된 값을 넣어 검증할 수 있게 바꿨습니다. (사실, 이 때 AfterEach를 쓰지않고 그냥 @Transactional을 사용해서 테스트가 깨지는지 바로 몰랐어요. 그대로 안해서 죄송해요 ㅠ)

 

IntegrationTestSupport로 환경통합하는 섹션 듣는중에, 변경감지가 동작하지 않아서 디버깅해보니깐, stock.deductQuantity에서 변경감지가 동작하지 않더라구요. @Transactional을 붙여서 해결은 했는데 왜 동작이 안한건지 궁금합니다.

 

https://drive.google.com/file/d/1E9-pN1QbrCyZ1w2G5CSP7JtnB6c7SFPf/view?usp=drive_link

답변 2

1

박우빈님의 프로필 이미지
박우빈
지식공유자

안녕하세요, 구준형 님!

말씀주신 내용을 정리하면, 기존에는 OrderService에 트랜잭션이 걸려있지 않았으나 테스트 클래스에 트랜잭션이 걸려있어서 테스트가 깨지지 않았는데, 이후 테스트 코드 리팩토링을 하면서 OrderService에 트랜잭션이 걸려있지 않은 것이 드러나 테스트가 깨진 상황 같네요. (링크로 주신 구글 드라이브는 권한이 없어서 보이질 않네요 ㅠㅠ)

JPA의 변경 감지에 대해 학습을 해보시면 아시겠지만, 변경 감지라는 것은 엔티티 매니저가 flush라는 행위를 하는 시점에, 영속성 컨텍스트에 저장된 초기 상태(스냅샷)와 현재 엔티티에 차이점이 발생했는지를 비교해서, update 쿼리를 생성하여 변경 사항을 DB에 반영하는 과정인데요.

이 flush라는 행위는 트랜잭션 커밋이 되는 시점에 수행됩니다.
즉, 변경 감지는 트랜잭션 범위 내에 있어야 발생하고, OrderService 내에서 발생한 변경 사항을 변경 감지 기능으로 DB에 반영하고 싶다면 트랜잭션이 반드시 필요한 것이죠.

도움이 되셨기를 바랍니다.
감사합니다 🙂

 

구준형님의 프로필 이미지
구준형
질문자

아 감사합니다! 혼자 생각정리하다보니, 알게되었어요. 사진처럼 new로 생성한 OrderService라서 빈으로 관리되는게 아니다보니 @Transactional이 동작하지 않은것이였네요.
좋은 강의 감사합니다. 도움 많이 되었어요.

박우빈님의 프로필 이미지
박우빈
지식공유자

아하, 그런 것이었군요 👍

0

안녕하세요, 인프런 AI 인턴입니다.

님이 마주하신 문제는 @Transactional의 사용과 변경 감지에 관련된 일반적인 이슈로 보입니다. JPA에서 @Transactional 어노테이션이 붙은 메소드나 클래스에서만 변경 감지(dirty checking)가 사용 가능합니다. 이 변경 감지 기능은 JPA가 데이터베이스와의 세션 내에서 엔티티의 상태 변화를 추적하고, 트랜잭션이 종료될 때 변경 사항을 데이터베이스에 자동으로 반영하도록 합니다.

stock.deductQuantity에서 변경 감지가 동작하지 않은 것은 해당 메소드가 실행될 때 @Transactional의 적용 범위 밖에 있었을 가능성이 큽니다. 이 경우, JPA는 그 메소드에서 엔티티의 상태가 변했음을 인지하지 못하고, 따라서 엔티티 상태의 변경을 데이터베이스에 반영하지 않습니다. @Transactional을 메소드에 추가하면, 그 메소드 전체가 하나의 트랜잭션으로 처리되어 메소드 내에서 발생한 엔티티의 모든 상태 변화가 트랜잭션이 성공적으로 완료될 때 데이터베이스에 반영됩니다.

따라서, @Transactional 어노테이션을 붙여 해결하셨다면, 그것은 변경 감지 기능이 트랜잭션 범위 내에서 정상적으로 작동하기 시작했기 때문입니다. JPA와 스프링 데이터 JPA를 사용할 때는 @Transactional의 범위와 사용 방법에 대해 정확히 이해하는 것이 중요합니다.