본문 바로가기
Homo Coding

테스트 DB 스키마 관리

by javauser 2009. 11. 12.

Unitils에서는 테스트 DB 스키마를 관리할 수 있는 메커니즘을 제공한다.
이는 다음과 같은 속성을 통해 설정할 수 있다.

updateDataBaseSchema.enabled=true
dbMaintainer.script.locations=scripts
dbMaintainer.autoCreateExecutedScriptsTable=true
dataSetStructureGenerator.xsd.dirName=target/xsd

위의 속성에서 dbMaintainer.script.locations=scripts은 DDL 이 위치하는 디렉토리를 의미하며, 통상 maven 환경에서 src/test/resource 하위에 scripts 라는 디렉토리 밑에 확장자가 .sql 이나 .ddl 로 저장된 파일이 위치하게 된다.

DDL 파일명은 001_initial.sql 처럼 맨 앞의 이름이 숫자로 지정되며, Unitils가 자동으로 높은 숫자의 파일을 실행하게 된다. 즉, DB 스키마에 대한 버전 관리가 가능하다.

하지만, DB 스키마를 개별 컴포넌트(maven 프로젝트)에서 분리되어 관리되는 형태보다는 한군데서 관리하고, 이를 지속적으로 유지하는게 나을 수도 있다. 이 경우에는 각 maven 프로젝트마다 있는 DDL 구문을 한군데에 모으는 작업이 필요하며, 이 한군데에 모여진 DDL을 가지는 maven 프로젝트를 dependency를 추가해서 사용하는 방법이 나을 수도 있다. 이를 위해서는 Unitils의 위의 설정 (DDL 파일이 위치한 장소를 지정하는 부분)이 물리적인 디렉토리 구조로 접근하는 방식이 아닌, 클래스패스 상의 DDL을 접근하는 방식을 취하도록 바꿔주는게 필요한데, Unitils에서는 ScriptSource가 이에 해당한다.

Unitils의 기본 설정에서
org.unitils.dbmaintainer.script.ScriptSource.implClassName=org.unitils.dbmaintainer.script.impl.DefaultScriptSource

이와 같은 부분이 있다. 이 DefaultScriptSource가 위의 dbMaintainer.script.locations=scripts 설정을 통해 DDL 스크립트를 만드는 클래스로 이를 확장하면 클래스패스 상의 DDL 스크립트를 가지고 와서 다른 maven 프로젝트에서 사용이 가능하다.

다음은 DefaultScriptSource를 확장하여 클래스패스 상의 DDL 스크립트를 사용하도록 하는 코드이다.

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.unitils.core.UnitilsException;
import org.unitils.dbmaintainer.script.Script;
import org.unitils.dbmaintainer.script.impl.DefaultScriptSource;
import org.unitils.util.PropertyUtils;

public class ClasspathScriptSource extends DefaultScriptSource {

 @Override
 protected List<Script> loadAllScripts() {
  List<String> scriptLocations = PropertyUtils.getStringList(PROPKEY_SCRIPT_LOCATIONS, configuration);
  List<Script> scripts = new ArrayList<Script>();
  
  for (String scriptLocation : scriptLocations) {
   getScriptsAt(scripts, scriptLocation, "");
  }
  
  return scripts;
 }

 @Override
 protected void getScriptsAt(List<Script> scripts, String scriptRoot,
   String relativeLocation) {
  DefaultResourceLoader defaultResourceLoader = new DefaultResourceLoader(Thread.currentThread().getContextClassLoader());
  Resource resource = defaultResourceLoader.getResource(scriptRoot + "/" + relativeLocation);
  File currentLocation = null;
  try {
   currentLocation = resource.getFile();
  } catch (IOException e) {
   throw new UnitilsException("File location " + scriptRoot + " defined in property " + PROPKEY_SCRIPT_LOCATIONS + " doesn't exist");
  }
  
  if (currentLocation.isFile() && isScriptFile(currentLocation)) {
          Script script = createScript(currentLocation, relativeLocation);
          scripts.add(script);
          return;
      }
      // recursively scan sub folders for script files
      if (currentLocation.isDirectory()) {
          for (File subLocation : currentLocation.listFiles()) {
              getScriptsAt(scripts, scriptRoot,
                      "".equals(relativeLocation) ? subLocation.getName() : relativeLocation + "/" + subLocation.getName());
          }
      }
 }

}


위의 코드의 getScriptAt 메소드를 보면 SpringFramework의 DefaultResourceLoader를 사용함을 알 수 있으며, 이는 SpringFramework에서 사용하는 클래스패스 지정 방식 (예, classpath:/scripts) 으로 사용이 가능함을 알 수 있다.

이제 Unitils의 설정 파일의 내용을 다음과 같이 수정해야 한다.

org.unitils.dbmaintainer.script.ScriptSource.implClassName=com.company.ClasspathScriptSource

updateDataBaseSchema.enabled=true
dbMaintainer.script.locations=classpath:/scripts
dbMaintainer.autoCreateExecutedScriptsTable=true
dataSetStructureGenerator.xsd.dirName=target/xsd

이제 DDL을 한군데서 관리하는게 가능해진다.

반응형