티스토리 뷰

TDD, 클린 코드 with Java 교육 중에 메모리 DB를 효율적으로 사용할 수 있는 방법을 배워, 샘플 코드와 함께 정리를 해두려고 한다. 이걸 잘 활용하면, 실무에서 초기 개발 환경 세팅을 눈에 띄게 편하게 만들 수 있을 것 같다 🔥

 

 

복잡한 과정들에서 한 스텝 이상은 줄일 수 있을거라 확신한다

 

1.  개요

기존 방식의 문제점: 테스트용 파일 DB

그동안 실무에서 DB에 의존적인 코드를 테스트하기 위해서는 아래와 같은 순서로 보통 작업을 했었다. 문제는 테스트를 위한 DB 파일을 관리해야 한다는 것이고, 테이블이 변경될 때마다 DB 파일도 함께 업데이트 해야한다는 점이다.

- (h2 기준으로) 테스트용 DB 파일 생성
- properties(혹은 yml)에 DB 경로 설정
- 테이블이 변경될 경우, 테스트용 DB 파일을 수정

 

인메모리 DB가 있다는 건 알고 있었지만, test fixture를 위해 어디에선가는 DB에 insert를 해줘야했기 때문에 파일 DB를 쓰는게 낫다라고 생각했었다.

 

 

개선: 어플리케이션 실행 시, DDL, DML 스크립트 실행

스프링 어플리케이션 실행 시 resources 경로에 있는 schema.sql(DDL)과 data.sql(DML) 스크립트를 실행하는데, 이를 활용하면 테스트를 위한 DB 파일을 사용하지 않고 인메모리 DB를 활용해 테스트를 수행할 수 있다.

 

 

2.  프로젝트 준비

build.gradle 설정

스프링 부트 버전은 2.7.12이고, DB는 h2hibernate로 테스트 하기 위해 의존성은 아래와 같이 추가했다.

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
}

 

schema.sql(ddl)

샘플이 될 예제는 최대한 간단히 만들었다.

create table book (
    id bigint,
    title varchar(255),
    price integer,
    primary key (id)
);

 

data.sql(dml)

insert into book values(1, 'TDD', 12000);
insert into book values(2, 'CLEAN CODE', 19000);
insert into book values(3, 'JPA', 18000);

 

application.yml

인메모리 DB를 위한 설정과 hibernate를 통해 ddl이 실행되지 않도록 spring.jpa.hibernate.ddl-auto: none 설정

spring:
  datasource:
    url: jdbc:h2:mem:testdb
  jpa:
    hibernate:
      ddl-auto: none
logging.level:
  org.hibernate.SQL: debug
  org.springframework.jdbc: debug

 

 

3. 어플리케이션 구성

domain

위에서 작성한 book 테이블과 매핑되는 엔티티

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@EqualsAndHashCode
public class Book {
    @Id
    private Long id;
    private String title;
    private int price;
}

 

infrastructure

@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
}

 

 

4. 테스트

테스트는 별도의 test fixture를 생성하지 않고, book 테이블 레코드를 모두 읽어서 결과를 비교했다. 인메모리 DB를 사용하고 있으므로, 초기 데이터가 insert되지 않으면 성공할 수 없지만…

@SpringBootTest
class LoadingInitialDataTestApplicationTests {
    @Autowired
    private BookRepository bookRepository;

    @Test
    void find_all() {
        List<Book> foundBooks = bookRepository.findAll();

        assertThat(foundBooks).containsExactlyInAnyOrder(
                new Book(1L, "TDD", 12000),
                new Book(2L, "CLEAN CODE", 19000),
                new Book(3L, "JPA", 18000)
        );
    }
}

 

테스트 결과: 성공

 

ddl, dml

테스트 시, create, insert문이 수행되는 것을 로그로 확인할 수 있다.

 

select

당연히 select문도 수행

 


샘플 코드 🤓

 

참고 자료 🙇‍♂️

댓글