테스트 코드에서의 주의점
@Transactional을 테스트 메서드에 직접 선언해야 하는 이유는 다음과 같습니다:
- 테스트 클래스는 일반적으로 @SpringBootTest로 실행되며, 내부적으로 프록시 기반 AOP가 적용됩니다.
- 하지만 JUnit의 테스트 메서드는 프록시 대상이 아니기 때문에, 클래스에 @Transactional을 선언해도 메서드에 직접 선언하지 않으면 적용되지 않을 수 있습니다.
- 특히 @Transactional을 클래스에 선언하고 @Test 메서드에서 DB 접근을 할 경우, 트랜잭션이 제대로 적용되지 않아 LazyInitializationException이나 rollback이 되지 않는 문제가 발생할 수 있어요.
- 테스트에서 트랜잭션을 적용하고 싶다면 테스트 메서드에 직접 @Transactional을 붙이는 것이 안전
또는 @OneToMany 선언된 곳을 아래와 같이 수정
@OneToMany(mappedBy = "question", cascade = CascadeType.REMOVE)
@OneToMany(mappedBy = "question", cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
Spring에서 말하는 Proxy Mode는
AOP(Aspect-Oriented Programming)나 트랜잭션 처리 같은 기능을 적용하기 위해 프록시 객체를 생성하는 방식을 의미해요. 이 프록시는 실제 객체를 감싸서 메서드 호출을 가로채고, 필요한 부가 기능을 수행한 뒤 실제 메서드를 실행하게 됩니다.

Proxy Mode가 사용되는 대표적인 예
- @Transactional: 트랜잭션을 자동으로 관리하기 위해 프록시를 생성
- @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS): 스코프가 다른 빈을 주입할 때 프록시를 사용
- @EnableAspectJAutoProxy(proxyTargetClass = true): AOP 적용 시 CGLIB 방식 강제
테스트 메서드에서의 프록시 한계
테스트 메서드는 일반적으로 프록시 객체로 감싸지지 않기 때문에, @Transactional 같은 어노테이션이 제대로 작동하지 않을 수 있어요. 그래서 테스트에서는 직접 메서드에 @Transactional을 붙여야 트랜잭션이 적용됩니다.
🌱 “Spring이 QuestionRepository 타입의 빈(bean)을 찾아...”란?
스프링 프레임워크는 의존성 주입(Dependency Injection) 을 통해 필요한 객체들을 자동으로 주입해줘요. 이 과정에서 “빈(bean)”이라는 단어가 아주 중요한데요:
빈(bean)이란?
- 스프링 컨테이너(Spring Container) 가 관리하는 객체를 뜻합니다.
- 우리가 @Component, @Service, @Repository, @Controller 등의 어노테이션을 붙이면 해당 클래스는 빈으로 등록됩니다.
- 빈은 스프링이 생성하고 필요할 때 꺼내서 사용하는 “등록된 객체” 라고 볼 수 있어요.
QuestionRepository는 어떻게 빈이 됐을까
@Repository
public interface QuestionRepository extends JpaRepository<Question, Integer> { }
- @Repository 어노테이션 또는 JpaRepository를 확장했다는 사실 때문에 스프링 부트는 자동으로 이 인터페이스를 구현한 객체를 만들고 빈으로 등록해요. (@EnableJpaRepositories가 내장되어 있음)
그래서 @Autowired는 뭘 하는가
- 이 코드가 실행되면 스프링은 컨테이너 안을 뒤져서 QuestionRepository라는 타입을 가진 빈이 있는지 확인합니다.
- 빈을 발견하면 해당 필드에 자동으로 주입해주는 거예요!
즉, 개발자가 new QuestionRepository()로 객체를 만들 필요 없이, 스프링이 알아서 등록된 인스턴스를 가져와 넣어준다는 뜻입니다.
Question/Answer Repository
@Repository //- Tells Spring this interface is part of the persistence layer. jpa 규칙
/* JpaRepository<Answer, Integer>: Inherits CRUD functionality.
→ 기본적인 생성(Create), 조회(Read), 수정(Update), 삭제(Delete) 기능 자동 제공.
- Answer: Entity class (엔티티 클래스)
- Integer: Primary key type (기본 키의 자료형)
* */
public interface AnswerRepository extends JpaRepository<Answer, Integer> {
}
@Autowired
@Autowired // 클래스 객체 생성 자동화
private QuestionRepository questionRepository;
- Spring이 QuestionRepository 타입의 빈(bean)을 찾아 자동으로 주입해주는 어노테이션이에요.
- 즉, 직접 객체를 생성하지 않아도 Spring이 알아서 필요한 객체를 넣어줍니다.
- 생성자나 setter를 사용하지 않고도 멤버 변수에 바로 주입할 수 있어요.
→ 쉽게 말하면, "Spring, 알아서 이 타입의 객체 좀 넣어줘!" 하는 거예요.
리포지터리로 데이터베이스 관리하기 H2
테스트 실행 → 실제 어플리케이션 실행, → H2 콘솔에서 확인하기

일련의 과정에서 로그 생성내역 확인 필요

또한 jpd 설정에 update 옵션 적용여부 확인