나는 JPA관련된 테스트는 H2를 사용하고, Native Query로 작성한 경우만 따로 MySQL을 사용한 테스트 환경을 구축했다.
H2와 MySQL간 문법 차이가 있기 때문에 Native Query테스트의 경우는 MySQL에서 테스트하는걸 권장한다.
Native Query는 JPA의 Action Queue때문에 쿼리 순서를 위해 사용했는데, 이건 주제와 상관없으니 설명은 따로 하지는 않겠다.
아무튼 이런경우 특정 DB를 사용하는 테스트를 위한 Config를 만드는게 좋다.
@TestConfiguration
public class TestDataSourceConfig {
@Bean
@Primary
public DataSource dataSource() {
Properties properties = new Properties();
properties.setProperty("useSSL", "false");
properties.setProperty("serverTimezone", "Asia/Seoul");
properties.setProperty("characterEncoding", "UTF-8");
properties.setProperty("allowPublicKeyRetrieval", "true");
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/database");
dataSource.setUsername("username");
dataSource.setPassword("password");
dataSource.setCatalog("catalog");
dataSource.setConnectionProperties(properties);
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource);
// 패키지 스캔 경로를 실제 엔티티들이 위치한 패키지로 지정
emf.setPackagesToScan("com.(경로).domains");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
emf.setJpaVendorAdapter(vendorAdapter);
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
jpaProperties.put("hibernate.hbm2ddl.auto", "create-drop");
// 필요한 추가 JPA 속성들을 설정
emf.setJpaProperties(jpaProperties);
return emf;
}
}
보통 다른 레퍼런스보면 dataSource만 설정해주는 경우가 있는데, entityManagerFactory까지 설정해줘야 ddl-auto도 적용된다.
만약 CI 스크립트에 테스트 파이프라인을 구축해놓았다면 ddl-auto 설정이 안되어있어 테스트가 터지는 경우가 발생할 수 있으니 설정을 꼭 확인하자.
default JPA인터페이스 구현체인 Hibernate를 사용하기 때문에 해당 Property에 대한 값을 세팅해주었다.
SQLException이나 Grammar 오류가 발생하면 EntityManagerFactory까지 TestConfiguration 안에 설정해주면 된다.
그리고 나서 테스트는 아래와 같이 작성해주었다.
@DataJpaTest
@ComponentScan(basePackages = {"com....domains.announce.repository"})
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import(TestDataSourceConfig.class)
public class AnnounceImageNativeRepositoryTest {
@Autowired private AnnounceImageNativeRepository announceImageNativeRepository;
@PersistenceContext private EntityManager entityManager;
@Nested
@DisplayName("....")
class ImageUpdateUnitTest {
@BeforeEach
public void setUpImages() {
...
}
}
...
}
Import어노테이션을 통해 TestConfig를 가져오고 해당 빈을 테스트에 한에서 컨텍스트에서 관리하게 해준다.
ComponentScan을 사용한 이유는, 멀티모듈 구조로 프로젝트를 관리하기 때문에 다른 모듈에 있는 Component인 경우 명시적으로 Scan해주어야 하기 때문이다.