문제 상황
H2 데이터베이스에 연결한 상태로 JPA에 대한 테스트 코드를 작성하는 도중 테이블이 정상적으로 생성되었음에도 아래와 같은 "테이블을 찾을 수 없다"는 에러 메세지를 보게되었고, 해당 문제를 해결하기 위해 @DataJpaTest에 대해 찾아보았다.
could not prepare statement [Table "ARTICLE" not found (this database is empty); SQL statement:
@DataJpaTest
@DataJpaTest는 JPA에 대한 테스트 실행 시 테스트를 위한 내장 데이터베이스를 생성해서 실제 DB에 영향을 주지않고 테스트 할 수 있도록 환경을 제공해준다.
@DataJpaTest의 동작 과정은 EntityScan을 통해 Entity들을 읽어 스키마를 생성하고 내부 어노테이션을 보면@AutoConfigureTestDatabase를 통해 내장형 데이터베이스를 생성해서 테스트할 수 있고, @Transactional 어노테이션이 붙어있어 따로 트랜잭션 처리를 해주지않아도 된다.
문제 해결
@DataJpaTest의 동작 방식과 에러 로그를 통해 문제를 찾을 수 있었다.
아래 에러 로그를 보면 H2 In memory DB에 연결이 된 것을 확인할 수 있다.(url에 mem이 들어가면 메모리 DB라는 뜻이다)
2023-12-31T19:22:36.577+09:00 INFO 60688 --- [ Test worker] o.s.j.d.e.EmbeddedDatabaseFactory : Starting embedded database: url='jdbc:h2:mem:2f9bafde-d92c-4c5a-a7df-d4d7fab806f3;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'
하지만 나는 아래와 같이 디스크 형식의 H2 데이터베이스와 MySQL 문법을 적용하도록 설정해주었다.
여기서 문제는 테스트를 위해 연결된 In memory H2 데이터베이스는 MySQL 문법이 적용이 되지 않았고, UserAccount의 "TINYINT(1) default false" 문법이 H2 문법에 맞지않아 에러를 발생시킨 것이었다.
spring:
datasource:
url: jdbc:h2:tcp://localhost/~/h2test;MODE=MYSQL
driver-class-name: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: create
database-platform: org.hibernate.dialect.MySQL8Dialect
show-sql: true
@EntityListeners(AuditingEntityListener.class)
@Entity
public class UserAccount extends AuditingField{
...
@Column(nullable = false, columnDefinition = "TINYINT(1) default false")
private boolean isWithdraw;
...
}
따라서 아래와 같이 @AutoConfigureTestDatabase의 replace 옵션을 NONE으로 설정하여, 내장 테스트 데이터베이스를 생성하지 않고 기존 데이터베이스에 연결하여 테스트 할 수 있도록 변경해주어 문제를 해결할 수 있었다.
@AutoConfigureTestDatabase(replace = Replace.NONE)
@DataJpaTest
class JpaRepositoryTest {
....
}
2023-12-31T19:29:41.419+09:00 INFO 60816 --- [ Test worker] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:tcp://localhost/~/h2test user=SA
2023-12-31T19:29:41.421+09:00 INFO 60816 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2023-12-31T19:29:41.441+09:00 WARN 60816 --- [ Test worker] org.hibernate.orm.deprecation : HHH90000025: MySQL8Dialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
2023-12-31T19:29:41.442+09:00 WARN 60816 --- [ Test worker] org.hibernate.orm.deprecation : HHH90000026: MySQL8Dialect has been deprecated; use org.hibernate.dialect.MySQLDialect instead
다른 해결 방법으로 다음과 같이 defer-datasource-initialization: true 설정하고 @DataJpaTest에 @Sql(scripts = {"classpath:data.sql"})를 붙여서 data.sql 파일로 테스트 스키마와 데이터를 넣어줄 수 있다.
Reference
https://goateedev.tistory.com/288
https://pasudo123.tistory.com/394
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!