[Spring DB 2편] 3. DB와 테스트

HJ·2023년 2월 2일
1

Spring DB 2편

목록 보기
3/11
post-custom-banner

김영한 님의 스프링 DB 2편 - 데이터 접근 활용 기술 강의를 보고 작성한 내용입니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard


1. DB와 연동한 테스트

  • @SpringBootTest@SpringBootApplication 가 붙은 클래스를 찾아 해당 클래스의 설정을 사용한다

  ➜ 해당 클래스의 @Import에서 JdbcTemplateV3Config.class 를 사용

  ➜ 테스트도 JdbcTemplate 을 통해 실제 DB를 호출한다

  ➜ 테스트에서 실제 DB를 호출하면 기존 DB에 있던 데이터들로 인해 영향을 받는다

  ➜ 즉, 로컬에서 사용하는 어플리케이션 서버와 테스트가 같은 DB를 사용하기 때문에
   문제가 발생할 수도 있다

  ➜ 테스트 전용 데이터베이스를 별도로 운영해서 문제를 해결한다




2. DB를 분리한 테스트

  • H2 에서 jdbc:h2:~/testcase에 접속해 test용 DB 생성 ( 최초 1회 )

  • /test/resources 하위의 application.properties에 테스트용 DB로 설정 정보 변경

    • spring.datasource.url=jdbc:h2:tcp://localhost/~/testcase
  • but> DB를 분리해도 메모리가 아니기 때문에 이전 테스트로 인해 저장된 데이터가 유지

  ➜ 반복 테스트를 위해 트랜잭션을 활용해 각 테스트가 끝날때마다 DB를 롤백시킨다




3. 데이터 롤백

3-1. 설명

  • 트랜잭션 시작 ➜ 테스트 실행 ➜ 트랜잭션 롤백 과정을 반복

  • 테스트가 끝난 후 트랜잭션을 강제로 롤백시키면 테스트하면서 추가한 데이터가 제거된다

  • 테스트하면서 데이터를 저장했는데 중간에 테스트가 실패해서 롤백을 호출하지 못해도 커밋하지 않았기 때문에 DB에 반영되지 않는다

  • 데이터를 커밋하지 않아도 같은 세션에서는 임시로 추가한 데이터를 조회할 수 있기 때문에 테스트를 수행하는데 문제가 발생하지 않는다


3-2. 테스트에 적용

class ItemRepositoryTest {

    @Autowired
    PlatformTransactionManager transactionManager;
    TransactionStatus status;

    @BeforeEach
    void beforeEach() {
        // 테스트 전, 트랜잭션 시작
        status = transactionManager.getTransaction(new DefaultTransactionDefinition());
    }

    @AfterEach
    void afterEach() {
        // 테스트 후, 트랜잭션 롤백
        transactionManager.rollback(status);
    }
}
  • 트랜잭션 매니저는 PlatformTransactionManager 를 주입 받아서 사용

  • 스프링부트는 자동으로 적절한 트랜잭션 매니저를 스프링 빈으로 등록해준다

  • @BeforeEach : 테스트 전에 호출되며, 여기서 트랜잭션을 시작

  • @AfterEach : 테스트 후에 호출되며, 여기서 트랜잭션을 롤백

  • Repository 에서는 트랜잭션 동기화 매니저를 통해 커넥션을 획득하기 때문에 같은 커넥션을 사용하게 된다




4. @Transactional

  • 스프링은 트랜잭션을 적용하고 롤백하는 방식을 @Transactional 하나로 처리한다

  • 클래스 레벨에 @Transactional 를 붙이게 되면 테스트 내 모든 메서드에 적용된다

  • @Transactional 은 로직이 성공하면 커밋되는데 어떻게 테스트에서 사용이 가능할까?

  @Transactional이 테스트에 있으면 스프링은 테스트를 트랜잭션 안에서 실행하고
   테스트가 끝나면 트랜잭션을 자동으로 롤백시킨다

  • 트랜잭션 시작 ➜ 테스트를 실행하면 모든 로직은 트랜잭션 안에서 실행 ➜ 끝나면 롤백

  • 참고> 테스트 종료 후 커밋하기 : @Commit@Rollback(value=false) 를 사용

  • 참고> Service나 Repository에 @Transactional 이 있는 경우, Test에서 트랜잭션이 시작되었다면 Service나 Repository의 @Transactional이 테스트의 트랜잭션에 참여




5. 임베디드 모드 DB

5-1. 설명

  • 테스트용으로 DB를 사용하면 종료 후 데이터를 전부 삭제하거나 DB 자체를 제거해도 된다

  • H2는 JVM 안에서 메모리 모드로 동작하는 기능이 있는데 이를 임베디드 모드라고 한다

  • 즉, 어플리케이션을 실행할 때 H2도 JVM 메모리에 포함해서 실행할 수 있다

  • 어플리케이션이 종료되면 임베디드 모드로 동작하는 H2 종료 및 모든 데이터 삭제


5-2. 기본 설정

@SpringBootApplication
public class ItemServiceApplication {

	@Bean
	@Profile("test")
	public DataSource dataSource() {
		DriverManagerDataSource dataSource = new DriverManagerDataSource();
		dataSource.setDriverClassName("org.h2.Driver"); // H2 DB 드라이버 지정
		dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");	// 메모리 DB를 띄운다
		dataSource.setUsername("sa");
		dataSource.setPassword("");
		return dataSource;
	}
}
  • 데이터 소스를 만들때 jdbc:h2:mem:db 로 설정하면 임베디드 모드로 동작하는 H2 데이터베이스를 사용할 수 있다

  • 임베디드 모드에서는 데이터베이스 커넥션 연결이 모두 끊어지면 데이터베이스도 종료되는데, DB_CLOSE_DELAY=-1가 이를 방지하는 설정이다

  • but> 이렇게 설정한 후 테스트를 실행하면 오류가 발생

  ➜ 메모리 DB는 어플리케이션이 종료될 때 함께 사라져서 테이블이 없기 때문


5-3. SQL 스크립트

  • 테이블 생성을 위해 JDBC나 JdbcTemplate으로 테이블을 생성해도 되지만 불편하다

  • 스프링부트는 SQL 스크립트를 실행해서 어플리케이션 로딩 시점에 DB를 초기화한다

  • resources 하위에 schema.sql 이라는 이름으로 SQL 파일을 만들어야한다

  • SQL 파일에 테이블 생성 쿼리를 작성하면 메모리 DB가 생성될 때마다 테이블이 생성된다




6. 스프링부트와 임베디드 모드

  • 스프링부트는 임베디드 DB에 대한 설정도 기본으로 제공한다

  • 또한 DB에 대한 별다른 설정이 없으면 임베디드 DB를 사용한다

  • application.properties에 설정한 DB 정보와 임베디드 DB를 위한 DataSource 설정을 없애면 스프링부트는 임베디드 모드로 접근하는 DataSource 를 만들어서 제공한다

post-custom-banner

0개의 댓글