테스트 코드를 작성하면서 메인 어플리케이션과 DB 분리의 필요성을 느끼고 h2 database를 사용해 테스트 용 DB를 따로 만들어보았다.
나중에 또 사용할 때를 위해 과정을 기록해두어야겠다.
1. h2 설치
인메모리모드로 사용시 필수로 설치 하지 않아도 된다.
2. h2 데이터 베이스 모드 설정
h2 데이터 베이스는 3가지 모드로 동작 시킬 수 있다.
1) In-Memory Mode
url : jdbc:h2:mem:<databaseName>
2) Embedded Mode
url : jdbc:h2:[file:][<path>]<databaseName>
3) Server Mode
url : jdbc:h2:tcp://<server>[:<port>]/[<path>]<databaseName>
3. In - Memory h2 데이터 베이스 환경 구축
1) build.gradle에 h2 dependency 추가
dependencies {
testRuntimeOnly 'com.h2database:h2'
}
2) application-test.yml 파일 생성
spring:
config:
activate:
on-profile: test
datasource :
url: jdbc:h2:mem:test;MODE=MYSQL;
driverClassName: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: create #애플리케이션 시작 시 스키마 생성
database-platform: org.hibernate.dialect.H2Dialect
properties:
hibernate.show_sql: true
hibernate.format_sql: true
hibernate.use_sql_comments: true
open-in-view: false
application-test.yml 파일을 설정을 통해서 테스트 코드에서는 H2 인메모리 데이터베이스를 사용하고, 메인 애플리케이션에서는 application.yml 파일 설정을 통해서 MySQL 등 다른 데이터 베이스를 사용하도록 할 수 있다.
4. test 코드에만 적용되는 프로파일 설정
통합 테스트에서 게시글 생성 테스트를 할 때, userRepository에 저장되어있는 user 정보를 가져와야하는 로직이 있었다.
그러려면 user가 이미 테스트용 데이터베이스에 존재해야하는데 h2가 인메모리모드라서 테스트 코드 실행이 끝나면 데이터가 모두 휘발되기때문에 실행했을 때 미리 유저 데이터를 하나 넣어줘야했다.
처음에는 resources 디렉토리 하위에 import.sql 파일을 생성해서 유저정보를 insert하는 쿼리를 작성하려고 했다. 하지만 나는 인메모리모드라서 데이터베이스 스키마와 테이블을 포함한 모든 데이터가 존재 하지 않아 쿼리문에서 테이블 인식이 안 되는 문제가 발생했다.
+24.06.27 더 공부해보니 schema.sql로 table을 생성해주는 쿼리문을 작성해주면 import.sql이 오류나지 않고 정상 작동한다.
이를 해결하려면 인메모리모드외에 다른 모드 사용하여 데이터가 휘발되지 않고 남도록 하거나, 인메모리를 사용하고 싶다면 다른 방법을 찾아야했는데 다른 방법을 찾기로 했다.
어노테이션 @ActiveProfiles 와 @Profile 사용하여 이 문제를 해결 할 수 있었다.
@Component
@Profile("test") //test 프로파일에서만 활성화 되는 클래스
public class DataInitializer {
@Autowired
private UserRepository userRepository;
@PostConstruct
public void init(){
//초기 데이터 삽입
User user = new User("ggumi12345", "Ggumi1234567!", "김꾸미", "ggumi@gmail.com", "안녕하세요", Status.UNAUTHORIZED);
userRepository.save(user);
}
}
초기에 있어야하는 데이터를 @PostConstruct를 사용해 설정해주고 @Profile을 사용해 "test" 프로파일이 활성화 될 때만 이 클래스가 빈으로 등록되도록 할 수 있다.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) // 서버의 PORT 를 랜덤으로 설정합니다.
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // 테스트 인스턴스의 생성 단위를 클래스로 변경합니다.
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ActiveProfiles("test")
public class FeedServiceIntegrationTest {
@Autowired
FeedService feedService;
@Autowired
UserRepository userRepository;
@Autowired
FeedRepository feedRepository;
}
테스트 클래스에 @ActiveProfiles을 사용하여 테스트 실행 시에 활성화할 프로파일을 지정해 줄 수 있다.
이 두 방법을 사용하여 테스트 코드가 실행될 때만 H2 데이터 베이스를 사용함과 동시에 초기에 유저 데이터를 삽입해야하는 문제를 해결하였다.
어노테이션 정리
@ActiveProfiles: 주로 테스트 클래스에 적용되고, 테스트 실행 시 활성화할 프로파일을 지정하는 역할을 한다.
@Profile: 구성 클래스, 빈 정의, 또는 컴포넌트에 적용되고, 특정 프로파일이 활성화된 경우에만 해당 빈을 등록한다.
이러한 단계를 통해 결과적으로 통합 테스트를 메인 애플리케이션 환경에서 분리할 수 있었다 !
'개발 > Spring' 카테고리의 다른 글
[Spring] Bean 등록하기 (@Bean vs @Component) / 같은 타입의 Bean 구분하기 (@Primary vs @Qualifier()) (0) | 2025.02.05 |
---|---|
[Spring] Spring AOP (0) | 2024.06.13 |
[Spring] 단위 테스트 (1) | 2024.06.13 |
[Spring] 뉴스피드 팀 프로젝트 설계 (0) | 2024.06.04 |
[Spring] 특정 URL에서만 작동하는 서블릿 필터 만들기 (1) | 2024.06.03 |