2009년 9월 7일 월요일

Spring에서 Junit Test 사용하기 (for junit 3.8)

스프링이 제공 하는 여러 훌륭한 기능이 있습니다.
그중에서 개인적으로 큰 점수를 주는 건 테스트가
용이하다는 것입니다. 애자일 개발 방법론
중에서 테스트 기반 개발 방법은 필수죠.
실제로 스프링을 만든 로드존슨도 애자일 애호가 이기 때문에
어떻게 하면 테스트를 보다 쉽고 편리하게 할수 있을지 고민을
많이 했다고 합니다.

  • Junit 3.8
이 포스트는 junit3.8 기반에 Jnuit 테스트를 진행 하려고 합니다.
왜 하필 최신 버전이 아닌 3.8 버전을 설명 하는 이유는
크게 두가지 정도라고 생각 합니다.

첫째는 현재 개발 플랫폼이 JDK1.4 이하일 경우
,

두번째는 annotation에 대해서 팀원들이 이해가 부족하거나 혹은 이유 없이 그냥 사용하기 싫어서 .

솔직히 두번째 이유는 설득력 떨어지지만
그래도 실무에서는 자주 발생되더군요 ^^.
하지만 첫번째 이유에 대해서는 정말 중요하다고 생각 합니다.
프로젝트 하면서 항상 느끼는건
"개발자는 개발 스펙에 자유로울 수 없다" 입니다.
즉 협업 시스템에서 정해진 개발 스펙을 따라야 한다는 거죠.
항상 최신 스펙만으로 개발을 할 수 없다는 거죠.

  • 스프링에서 Junit 3.8 사용 방법
"Pro Spring"을 보면 3.8 기반에서 junit 사용법을 3가지로 설명 되어
있습니다.

  1. extend TestCase
TestCase 상속 받아서 "ClassPathXmlApplicationContext"
를 리턴하는 private 메서드를 작성해서
테스트 메서드(testXXX로 시작하는 메서드) 실행시 매번
"ApplicationContext"를 가져오는 방식 입니다.


2. extend AbstractSpringContextTests

스프링에서 제공하는 'AbstractSpringContextTests" 추상 클래스를
상속 받아서 "loadContext" 추상 메서드를 구현합니다.
각 테스트 메서드는 부모의 "getContext" 메서드를 호출 함으로써
"ApplicationContext"를 가져오는 방식 입니다.

3. AbstractDependencyInjectionSpringContextTests

스프링에서 제공하는 'AbstractDependencyInjectionSpringContextTests"
상속 받아서 "getConfigLocations()"를 구현 합니다.
두번째 방법과 유사 하지만 이 방법은 bean을 가져올때 별도의
설정 없이 스프링에서 제공하는 injection 방법으로 사용 할 수 있습니다.

  • AbstractDependencyInjectionSpringContextTests
3가지 방법 중에서 세번째를 선택 한 이유는 첫째 매번 테스트 메서드
실행시 context를 로드할 필요 없이 한번만 하면 됩니다.
두번째는 사용하기가 용이 합니다. TestUnit를 스프링 빈처럼
사용 하면 됩니다.

※만약 JUNIT 실행시 XML 파서 에러가 발생 되면
"xml-apis-2.0.2.jar"

다운 받아서 클래스 패스에 추가 하시기 바랍니다.


import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import com.secl.app.hops.pkm.services.DefaultService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DefaultUserServiceIntegrationTests extends
AbstractDependencyInjectionSpringContextTests {

private Logger logger = LoggerFactory.getLogger(this.getClass());

private DefaultService defaultService;

protected String[] getConfigLocations() {
String[] paths = new String[] {
"classpath:/app/test/context-datasource.xml",
"classpath:/app/test/context-transaction.xml",
"classpath:/app/test/context-query.xml",
"classpath:/app/test/context-user.xml", };
return paths;
}

public void setDefaultService(DefaultService defaultService) {
this.defaultService = defaultService;
}

public void testUnitTest() throws Exception {
logger.info(this.defaultService.junitTest().toString());
assertTrue(true);
}
}

※마치 Controller로 유사한 형태 입니다.
6 : 반드시 클래스를 상속 받아야 합니다.
10,21 ~ 23 : injection할 서비스 와 setter 함수를 선언 합니다.
12 ~ 19 : Spring 빈을 로드할 xml 파일을 선언 합니다.

  • 유의 사항
스프링 bean xml을 설계할때 (junit 3.8,4.x 공통)
단위 테스트를 고려하지 않고 설계할 경우가 있습니다.
이럴 경우 나중에 단위 테스트를 만들려고
할때 상당히 애매한 경우가 발생 합니다.
예를 들어서 database 관련 unit 테스트를 하려고 하는데
같은 xml에 jms나 mvc 관련 빈이 설정되면 context를 로더 할때
쓸모 없는 빈이 로딩 될 경우도 생기며 심지어는 업무 특성상
로딩이 되지 않는 경우도 발생 합니다.
그렇기 때문에 빈 xml 설계할 때는 항상 현 시스템이 단위
테스트 하는데 있어서 문제가 없는지 부터 파악 하시고
빈 xml을 설계 하시길 바랍니다. 특히 database 관련된 것들은
반드시 별도의 xml로 관리 하시길 바랍니다.

댓글 없음:

댓글 쓰기