Spring Boot JPA Test @DataJpaTest 기본 설정
- jpa관련 테스트(Entity, Repository)를 할때 @DataJpaTest를 이용해서 진행하면 JPA관련 Bean과 @Transactional 어노테이션이 달려있어서 테스트가 끝나면 Configuration만 주입받아서 빠르게 테스트를 진행할 수 있다.
- @Transactional 어노테이션이 달려있어서 테스트가 끝나면 롤백도 되어서 간단하게 결과를 확인할 수 있는 장점이 있다.
- MySQL, MSSQL, Oracle 처럼 다른 DB를 연동해서 사용할 수도 있지만, 이 글에서는 in-memory DB인 H2를 연동해서 테스트 하는 방법을 정리하고자 한다.
환경
SpringBoot : 2.7.3
Java : JDK11
MacOS : Monterey 12.5.1
h2 : h2:2.1.214
MacBookPro : 14 M1Pro
JUnit : JUnit5
- build.gradle
plugins {
id 'org.springframework.boot' version '2.7.3'
id 'io.spring.dependency-management' version '1.0.13.RELEASE'
id 'java'
}
group = #
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'com.h2database:h2'
}
tasks.named('test') {
useJUnitPlatform()
}
- Test Property Source
- yml 형식을 사용한다.
- main 디렉토리가 아닌 test 디렉토리의 resources를 사용한다.
- application-test.yml
spring:
config:
activate:
on-profile: test
datasource:
username: sa
password:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL
jpa:
hibernate:
ddl-auto: create-drop
properties:
hibernate.dialect: org.hibernate.dialect.MySQL8Dialect
hibernate:
format_sql: true
globally_quoted_identifiers: true
show-sql: true
generate-ddl: true
database-platform: org.hibernate.dialect.MySQL8Dialect
database: h2
h2:
console:
enabled: true
- spring.config.activate.on-profile : test
- profile 환경 설정을 test로 한다
- url : jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL
- h2 기반 인메모리 휘발성 테스트로 진행할것이기 때문에 h2:mem으로 설정했다.
- DB_CLOSE_DELAY=-1 :
- 기본적으로 데이터베이스에 대한 마지막 연결을 닫으면 데이터베이스가 닫힙니다.
- 데이터베이스를 열린 상태로 유지하기 위해 가상 머신이 살아있는 동안 메모리 내 데이터베이스의 내용을 유지한다
- http://www.h2database.com/html/features.html#connection_modes
- DATABASE_TO_UPPER=false:
- (기본값: true). true로 설정하면 인용되지 않은 식별자와 데이터베이스의 짧은 이름이 대문자로 변환됩니다.
- 테이블명이나 컬럼 이름을 소문자로 사용하기 위해서 false로 설정
- DATABASE_TO_LOWER = true로도 사용 가능
- https://www.h2database.com/javadoc/org/h2/engine/DbSettings.html
- MODE=MYSQL
- H2 DB의 호환 모드를 MySQL로 설정
- globally_quoted_identifiers: true
- 데이터베이스 테이블 자동 생성시 키워드나 예약어가 충돌되는 경우가 있습니다.
- true로 설정하면 충돌을 방지하기 위해 테이블명이나 컬럼명을 ` 로 감싸줍니다.
- https://www.popit.kr/%EA%B0%80%EC%A7%9C%EB%89%B4%EC%8A%A4%EC%95%84%EC%9B%83-%ED%95%98%EC%9D%B4%EB%B2%84%EB%84%A4%EC%9D%B4%ED%8A%B8-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%8A%A4%ED%82%A4%EB%A7%88/
- 다른 옵션들은 http://www.h2database.com/html/features.html 에 잘 나와있습니다.
Entity, Repository
@Getter
@Entity
@NoArgsConstructor
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private int age;
@Builder
public Member(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
}
@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
}
TestClass - MemberRepositoryTest
@ActiveProfiles("test")
@DataJpaTest
@TestPropertySource(locations = "classpath:application-test.yml")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class MemberRepositoryTest {
@Autowired
MemberRepository memberRepository;
@Test
void save() {
memberRepository.save(
Member.builder()
.age(1)
.email("email@email.com")
.name("name")
.build()
);
}
}
- @ActiveProfiles("test") : 테스트 시에 어떤 profile로 설정할지 구성한다.
- develop, prod로 설정하면 해당 profile로 실행한다.
- test 환경 설정으로 실행할것이기 때문에 test로 설정 하였다.
- @DataJpaTest : Spring에서 JPA 관련 테스트 설정만 로드한다. DataSource의 설정이 정상적인지, 제대로 생성 수정 삭제 조회 하는지 등의 테스트가 가능하다.
- @TestPropertySource(locations = "classpath:application-test.yml")
- @TestPropertySource 애노테이션을 사용해서 새로운 설정 Source를 정의하고 프로퍼티의 값을 오버라이딩 한다.
- locations 속성을 통해서 설정 파일의 위치를 변경할 수 있다. 또한 properties 속성을 통해 우선순위가 더 높은 속성을 추가할 수 있다.
- @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
- @DataJpaTest를 사용하면 자동으로 EmbededDatabase를 사용하기 때문에 내가 설정한 설정값들을 사용할 수 없다.
- 이 설정을 replace 해서 해당 설정이 동작하지 않고, 내가 설정한 설정파일대로 만들어진 DataSoruce가 Bean으로 등록된다.
- yml이나 properties에서 내가 설정한 설정파일대로 사용하려면 (내가 설정한 H2, MySQL,Oracle 등) NONE 옵션을 사용해서 사용해야 한다
반드시 주의해야 하는게,
기본 H2가 아닌 내가 설정한 H2대로 설정하려면
@AutoConfigureTestDatabase 이 옵션을 반드시 추가해야한다 그렇지 않으면 엄청난 고생을 하게 된다.
- @AutoConfigureTestDatabase는 기본적으로 h2 인메모리 기반 으로 테스트를 하는데 왜????
- 이 부분은 다른 글로 정리할것이다.. 이틀을 삽질을 했다.. - https://0soo.tistory.com/41
- syntax error가 무조건 난다..
- 예약어도 아닌데 테이블도 안만들어지고.. select insert 아무것도 안된다..
- 정상적으로 테스트가 되는것을 볼 수 있다.
'테스트 > JUnit' 카테고리의 다른 글
Junit5 AssertJ List 정렬 테스트 ( Check if list is sorted in junit) (0) | 2022.12.15 |
---|---|
RefectionTestUtils - private 필드 값 주입, private 테스트 (0) | 2022.12.13 |
JUnit5 - Java에서의 단위테스트5 Mock, Mockito, Stup (0) | 2022.08.21 |
JUnit5 - Java에서의 단위테스트4 Mock, Mockito (0) | 2022.08.21 |
JUnit5 - Java에서의 단위테스트3 - 테스트 인스턴스들 (0) | 2022.08.21 |