junit repository test - 서비스용DB mysql과 테스트DB h2사용
springboot, jpa, mysql 을 이용하여 간단한 crud기능만들었다고 가정했을때, repository를 대상으로 테스트코드를 짜서 junit테스트를 진행해보고자 한다.
여기서는 테스트코드를 짜는 방식에 대한 설명보다는 DB connection을 위한 설정, application.yml과 같은 설정파일, 어노테이션 설정 등 기본 환경설정을 어떻게 해야 하는지 위주로 설명하도록 하겠다.
웹서비스 과정에서 data가 실제 쌓이는 mysql을 대상으로 테스트코드를 실행하는 방법과 테스트용DB인 H2 DB를 사용하는 두가지 방법으로 나눠서 설명할 예정이다.
서비스용 DB인 mysql을 대상으로 한 TEST방법
먼저, build.gradle에 아래와 같이 spring-boot-starter-test를 추가해준다. 해당 라이브러리가 junit을 포함하고 있다. 그 외 web, jpa, mysql 관련 라이브러리는 테스트와 별개로 crud서비스를 위해 필요했을테니 이미 추가 돼 있거나 신규 생성이면 추가하면 된다.
build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'mysql:mysql-connector-java'
}
application.yml에서의 datasource설정과 jpa설정은 일반적인 웹서비스를 위한 mysql, jpa설정과 동일하다. 최대한 테스트만의 별도의 설정 없이 기존에 구성돼 있는 DB를 대상으로 테스트 하고자 함이다.
application.yml
server:
port: 8081
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/board?useSSL=false&allowPublicKeyRetrieval=true
username: aaaa
password: bbbb
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show_sql: true
format_sql: true
generate-ddl: true
hibernate:
ddl-auto: update
이제 아래의 test코드를 살펴보자. author라는 객체를 사용하여 DB에 값을 save한 다음, 다시 조회해와서 최초 저장하고자 한 객체와 동일한지 확인하는 간단한 테스트이다. 어노테이션을 위주로 살펴보자.
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class AuthorRepositoryTest {
@Autowired
private AuthorRepository repository;
@Test
public void save(){
Author author = new Author();
author.setName("junitName");
author.setEmail("junitEmail");
repository.save(author);
//.get()은 optional객체에서 값을 꺼내는 방법.
Author repoMember = repository.findByEmail(author.getEmail()).get();
//실행시, 정상적인 파란불
assertThat(author).isEqualTo(repoMember);
}
DataJpaTest 어노테이션
해당 어노테이션은 Transactional 어노테이션을 포함하고 있고, 테스트가 끝나면 자동 rollback을 수행하므로 기존 DB를 대상으로 테스트 한다 하더라도 문제가 발생하지 않는다.
AutoConfigureTestDatabase 어노테이션
위의 DataJpaTest어노테이션 기능에는 Default설정으로 DB커넥션을 H2, HSQLDB 등의 Embedded DB를 사용하도록 하는 설정이 있다. 그래서, mysql 이나 postgres같은 실제 서비스 DB를 대상으로 테스트하고자 한다면, AutoConfigureTestDatabase 어노테이션을 붙여 default 설정을 덮어 써야 한다.
"replace = AutoConfigureTestDatabase.Replace.NONE"이 문자중에 앞의 replace의 기본 값은 any이다. 여기서 any는 H2, HSQLDB 등의 embedded DB를 의미한다. 그래서, 이 설정을 NONE으로 바꿔줌으로서 application.yml에서 등록한 datasource bean인 mysql을 사용하게 된다.
별도의 테스트용 H2 DB 사용
먼저, build.gradle에 h2 선언을 추가한다.
implementation 'com.h2database:h2'
별도의 yml파일을 아래와 같이 application-test.yml이라는 이름으로 신규 생성하였다.
application-test.yml
spring:
config:
activate:
on-profile: test
jpa:
open-in-view: false
generate-ddl: true
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate:
show_sql: true
format_sql: true
h2:
console:
enabled: true
config:activate:on-profile이 별도로 추가된것 외에는 h2와 jpa관련 기본적인 설정만 위와 세팅하면 내장된 h2를 사용하여 datasource빈을 생성하여 실행될 것이다. config관련해서는 좀 더 아래에서 설명하도록 하겠다.
아래 테스트코드는 mysql 대상으로 했던 테스트코드와는 다소 다름을 알수 있다.
@DataJpaTest
@ActiveProfiles("test")
class AuthorTestDbRepository {
@Autowired
private AuthorRepository repository;
@Test
public void save(){
//위의 mysql대상으로 한 테스트코드와 동일
}
먼저, AutoConfigureTestDatabase 어노테이션을 제거하여 default 임베디드 DB인 h2를 커넥션하도록 기본설정값으로 원복시켰다.
또한 ActiveProfiles에 "test"라는 문자열을 세팅하였다. 이는 위에서 신규로 생성한 application-test.yml을 바라보라는 설정이다. 기본적으로 테스트코드에서 참조하는 application.yml설정파일은 main밑에 있는 파일을 참조 하게 되는데, 별도로 만든 설정파일을 바라보게 하려면 위와 같은 문자열로 config값을 지정하고, yml파일 내에서 config:activate:on-profile 형태로 테스트코드의 문자열과 같은 이름으로 mapping 시켜주면 된다.
주의점
테스트를 직접 해보면 알겠지만 인메모리 H2 DB로 설정한 뒤 테스트 하여도, 간단한 table의 경우 문제가 발생하지 않을 것이다.
다만, 테이블 구조와 쿼리가 복잡해지면 호환 문제가 분명 발생하게 될것이다. index를 설정하거나, foreignkey naming방식등에 있어서 mysql 또는 다른 DB와 H2가 호환되지 않는 문제가 발생할 수가 있다는 점을 참고하길 바란다.