동아리에서 springboot
로 마이그레이션을 진행하면서 중요한 점 중 하나는 기존 Spring 3
에서 동작하던 기능이 마이그레이션을 했을 때 그대로 동작해야하는 점이었다.
그래서 인수테스트
를 통해 기능이 이전과 같이 동작하는지 테스트를 하고 통과하면 코드를 올리는 방식으로 진행되고 있다고 했다
마이그레이션에 대해서 온보딩을 하며 테스트 과정에서 테스트마다 데이터베이스 초기화가 이루어지는 과정이 어떻게 동작하는지 코드를 보라고 해서 이 글을 작성하게 됐다
테스트 코드를 보니 AcceptanceTest
라는 클래스가 있었다. 이 클래스 내부에서 DBInitializer
를 사용중이었다.
이름을 보니 딱 봐도 이 클래스가 DB 초기화를 담당할 것 같아서 코드를 봤다
하나씩 뜯어보자
@TestComponent
public class DBInitializer {
private static final int OFF = 0;
private static final int ON = 1;
private static final int COLUMN_INDEX = 1;
private final List<String> tableNames = new ArrayList<>();
@Autowired
private DataSource dataSource;
@PersistenceContext
private EntityManager entityManager;
초기에 설정을 해주는 부분인것 같다
여기서 @PersistenceContext
어노테이션은 처음보는데 EntityManager
를 빈으로 주입할 때 사용하는 어노테이션이라고 한다.
@PersistenceContext
를 쓰는 이유는 EntityManager
를 쓸 때 여러 쓰레드가 동시에 접근하면 동시성 문제가 발생해서 쓰레드 간에는 공유해서는 안되기 때문이라고 한다.
이 어노테이션을 이용하면 스프링 컨테이너가 초기화되면서 EntityManager
를 Proxy
로 감싸고 호출 시마다 Proxy
를 통해 EntityManeger
를 생성해서 Thread-safe
를 보장해줘서 공유가 안된다고 한다.
다음은 findDatabaseTableNames()
메서드가 나온다
메서드명을 보면 DB table
들을 찾는 메서드인것 같다
private void findDatabaseTableNames() {
try (final Statement statement = dataSource.getConnection().createStatement()) {
ResultSet resultSet = statement.executeQuery("SHOW TABLES");
while (resultSet.next()) {
final String tableName = resultSet.getString(COLUMN_INDEX);
tableNames.add(tableName);
}
} catch (Exception e) {
e.printStackTrace();
}
}
첫번째 테이블부터 시작해서 List
에 저장해주는 메서드이다
private void truncate() {
setForeignKeyCheck(OFF);
for (String tableName : tableNames) {
entityManager.createNativeQuery(String.format("TRUNCATE TABLE %s", tableName)).executeUpdate();
}
setForeignKeyCheck(ON);
}
메서드명 그대로 findDatabaseTableNames()
메서드에서 저장한 테이블들을 차례대로 돌면서 truncate
하는 메서드이다
이걸로 테이블 초기화를 해주는 것을 볼 수 있다
private void setForeignKeyCheck(int mode) {
entityManager.createNativeQuery(String.format("SET FOREIGN_KEY_CHECKS = %d", mode)).executeUpdate();
}
이건 FK
검사를 활성화하거나 비활성화하는 메서드이다
테이블을 초기화할때 FK
가 설정되어 있으면 초기화가 안될수도 있어서 넣어놓은 메서드 같다
@Transactional
public void clear() {
if (tableNames.isEmpty()) {
findDatabaseTableNames();
}
entityManager.clear();
truncate();
}
마지막으로 위에 써놓은 메서드들을 전부 실행시켜 초기화 시키는 clear()
메서드이다
지금까지 우리 동아리에서 사용하는 테스트 코드를 실행할 때 DB
를 초기화 시키는 코드를 봤다
이 초기화하는 메서드는 모든 테스트를 실행시키기 전에 한번씩 실행이 되므로 이전에 테스트 했던 데이터들이 남아 있는 일이 없도록 해준다