spock 통합테스트를 하려는 과정이다.
나는 특정 조건에 따라 테스트 클래스에 @SpringBootTest, @DataJpaTest 둘 중에 하나를 적용하고 싶었다.
@Conditional 은 스프링 컨텍스트가 확인하는 것이기 때문에 스프링 컨텍스트가 생성된 이후에 동작한다.
@SpringBootTest, @DataJpaTest 이것들이 스프링 컨텍스트를 만드는 어노테이션인데 스프링 컨텍스트가 없는 시점에 이걸 조건적으로 적용하고 싶은거니까 애초에 @Conditional 은 못쓴다.
컴파일타임에 어노테이션이 고정된다(소스코드가 정해진다)
junit의 @ExtendWith 으로 조건적으로 액티브 프로필을 적용할 순 있다.
@ExtendWith(ConditionalTestExtension.class) 으로 쓰고
ConditionalTestExtension 파일 만들어서 다른 어노테이션의 falg를 읽던, 변수를 읽던 해서 조건 만듦.
하지만 프로필을 여러개 만들어야 하고 각각의 프로필을 사용할 테스트 클래스 또한 여러개 만들어야 한다.
(@ActiveProfiles("AAA"), @SpringBootTest 붙은 클래스 하나, @ActiveProfiles("BBB"), @DataJpaTest 붙은 클래스 하나)
똑같은 코드를 여러개 만드는건 불필요하다.
@ExtendWith는 스프링 컨텍스트가 생성되기 전에 동작하기 때문에 스프링 컨텍스트 없이도 된다.
1. 컴파일타임
- 어노테이션 고정
2. 런타임
- @ExtendWith 확인
- 정해진 프로필에 따라 실행할 테스트 클래스 결정
- 클래스에 적용된 어노테이션에 따라 스프링 컨텍스트를 띄우거나 안띄우거나
컴파일타임에 어노테이션을 동적으로 처리하는 방법은 Annotation Processor 를 사용하는 것이다.
위에 썼듯 컴파일타임에 어노테이션이 고정되는건데 Processor 가 먼저 돌아서 조건적으로 어노테이션 정하는 것
Annotation Processor 동작 과정
컴파일타임. @ABCTest를 감지해서 값에 따라 어노테이션 추가하게 작성해놓음
1. 자바 컴파일러가 소스코드를 컴파일할 때 @ABCTest 애노테이션을 발견
2. SpockTestProcessor가 활성화되어 process() 메서드 실행
3. @ABCTest 의 flag 값에 따라
- false면 @SpringBootTest 추가
- true면 @DataJpaTest 추가
런타임에는 이미 @SpringBootTest가 추가된 상태로 시작
이후 스프링 테스트 프레임워크는 추가된 @SpringBootTest를 기반으로 스프링 컨텍스트 구성
Lombok(롬복)이 이런식으로 동작
@SpringBootTest 애노테이션 처리 과정
● 컴파일 타임
1. Java 컴파일러가 바이트코드로 변환하기 전에 Annotation Processor 동작 (있으면)
2. Java 컴파일러가 소스 코드를 바이트코드로 변환
3. 애노테이션의 문법 검사만 수행
4. @SpringBootTest 등의 애노테이션은 메타데이터로 클래스 파일에 저장
● 런타임 - JUnit 테스트 실행 시
1. JUnit Platform이 테스트 클래스 로드
2. @ExtendWith(SpringExtension.class)에 의해 SpringExtension이 활성화
- @SpringBootTest에 기본으로 적용되어 있어서 동작하는 @ExtendWith (얘도 있으면 동작)
3. Spring TestContext Framework 동작
- TestContextManager가 테스트 컨텍스트 관리
- @SpringBootTest 애노테이션 감지
4. SpringBootTestContextBootstrapper 동작
- 스프링 부트 테스트에 필요한 설정 로드
- ApplicationContext 생성 및 구성
5. 애플리케이션 컨텍스트 초기화
자바 AST 조작을 하고 싶으면 com.sun.tools.javac.tree.JCTree 등의 라이브러리를 사용해서 가능은 한데 해킹의 영역이라 기본적으로는 못쓰게 되어 있음. 활성화가 안됨. 회색글자. 각 개발자가 IDE에서 컴파일러 설정 추가하면 사용할 순 있음.
settings - Annotation Processors 에 Enable annotation processing 체크하래서 했는데 왜 안돼...
-> 성공한 현재 안됐던 이유 파악 : 이 때 만들었던 Annotation Processor는 자바 컴파일러에서 동작하는 것이다. 나는 groovy 테스트코드를 실행했고 때문에 그루비컴파일러가 동작했기 때문에 Annotation Processor가 적용되지 않았다.
빌드 과정을 보면 그루비 컴파일러가 동작한 것을 확인할 수 있다.
런타임에 수정하기
@ExtendWith 은 클래스가 JVM에 로드되기 전에 실행되므로 바이트코드 수정 가능
Java Agent : JVM이 바이트코드 실행 전에 premain 메서드를 호출, 바이트코드 조작. 왜 안돼...
-> 성공한 현재 안됐던 이유 파악 : 모르겠음. 돼야할 것 같은데 왜 안됐지.
성공!!
런타임에 Groovy의 AST(Abstract Syntax Tree, 추상 구문 트리) Transformation을 사용하여 어노테이션 추가하기 (블로그 작성 완료)
Groovy 컴파일러 동작: Groovy 컴파일러가 소스 코드를 분석하고, AST를 생성하며, 지정된 Transformation을 실행합니다.
컴파일 타임(정적)
@GroovyASTTransformation 로 AST 조작
완료 후 Groovy 컴파일러에 의해 동적으로 .class(바이트코드)로 컴파일됨
----------------------------------------------
런타임
JUnit Test Runner 실행
JVM이 Groovy 컴파일러가 생성한 .class(바이트코드) 기반으로 테스트 실행
test context framework 내용 정리할 것
https://mangkyu.tistory.com/202
[Spring] 스프링 테스트 컨텍스트(Spring Test Context)와 트랜잭션 지원
이번에는 테스트를 위한 테스트 컨텍스트 프레임워크(Test Context Framework)에 대해 정리해보도록 하겠습니다. 아래의 내용은 토비의 스프링을 참고하여 정리한 내용입니다. 1. 스프링 테스트 컨텍
mangkyu.tistory.com
[Spring] 스프링 테스트 - 테스트 컨텍스트 캐싱, @SpringBootTest, @WebMvcTest
🌱 들어가기 전 이전 포스팅과 마찬가지로 스터디에서 맡은 '테스트' 파트에 대해서 블로그에 정리해보고자 한다 😊 테스트 쪽은 공식 문서도 생각보다 가독성이 너무 안 좋아서 최대한 간략
cl8d.tistory.com
Spring context가 필요한 어노테이션이 있다면(@SpringBootTest, @DataJpaTest, @ContextConfiguration, @SpringJUnitConfig 등) Test Context 생성 후 Application Context 생성됨
이런 어노테이션이 없다면 아무 context도 만들어지지 않음
1. Test Context 초기화
2. 테스트 클래스의 인스턴스 생성. 필드 초기화(null, 0, false 등)
3. setupSpec() 메소드 실행
4. 라이브러리 설정 정보 로그 - SLF4J, Java 버전, 메모리 및 플랫폼 관련 설정, Direct ByteBuffer 관련 정보, Netty 네트워크 관련 라이브러리, TCP 리소스 초기화, Reactor 리액티브 프로그래밍을 위한 라이브러리
5. Test Context 의존성 주입 및 테스트 환경 설정. 테스트에 필요한 환경 설정 프로퍼티 로드
6. Spring 로고 출력
7. Application Context 초기화 - 빈 생성 및 의존성 주입(빈들이 필요로 하는 객체들을 주입)
8. 테스트 메소드 실행 전마다 setup() 메소드 실행
9. 테스트 메소드 실행
'SpringBoot' 카테고리의 다른 글
@GroovyASTTransformation 컴파일타임 조작, 어노테이션 동적 적용 (0) | 2025.02.24 |
---|---|
호출 순서 TestBootstrapInitializer, TestExecutionListener, setupSpec, ApplicationContextInitializer (0) | 2025.01.10 |
spock @LocalServerPort 할당 시점, setup, setupSpec 차이 (0) | 2024.11.20 |
swagger ui 에서 json 이쁘게 출력하기 (springfox 2.9.2 -> 3.0.0) (0) | 2024.10.30 |
@Transactional 롤백 (0) | 2024.07.22 |
댓글