개발/Spring

[Spring] @DataJpaTest 사용 시 주의사항

뽀글뽀글 개발자 2023. 12. 31. 19:32

문제 상황

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://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.html

 

DataJpaTest (Spring Boot 3.2.1 API)

A set of exclude filters which can be used to filter beans that would otherwise be added to the application context.

docs.spring.io

https://goateedev.tistory.com/288

 

Spring Boot @DataJpaTest 에서 h2만 연동되는 문제

JUnit에서 Repository 테스트를 하기 위해, @SprintBootTest 대신에 @DataJpaTest 를 사용하여 테스트 코드를 작성 중인데 h2 대신에 실제 DB를 연동하려고 하지만 막상 실행해보면, h2 데이터베이스에 계속 연

goateedev.tistory.com

https://pasudo123.tistory.com/394

 

20200523 [jpa] 스프링부트 실행 시, 디비 데이터 삽입 및 테스트 코드 상에서 데이터 삽입. (수정 : 20

개요. 스프링부트 JPA 를 이용하려고 할 때, 실제 사용 DB 에 값을 넣지 않고 인메모리인 H2 를 사용해서 데이터에 대한 CRUD 코드를 작성하는 경우가 종종 있다. 이 때, 스프링부트 실행하는 시점에

pasudo123.tistory.com