Spring에서 TDD를 적용해본다.

여기서는 db가 구축되어 있고, db조회, 입력, 처리부분을 TDD로 테스트할 경우를 예를 들겠다.
(원래는 db도 DBUnit로 처리되어 있다면 아래처럼 할 필요는 없다. )

Spring에서 UI를 개발하기 전에 DB가 구축되어 있고, mybatis로 쿼리가 등록되어 있고, dao, service등의 클래스가 이미 만들어져 있어서 Controller에서 DB입력, 조회, 테스트만 하고 싶을 경우가 있다. 실제로 DB에 잘 입력이 되는지…

먼저 src/src/java에 TDD로 작성할 클래스를 선택하고 오른쪽 클릭 New>JUnit Test Case를 선택하면 아래의 창이 나온다.

Source folder 부분을 Browse버튼을 이용해서 src/test/java로 변경하고 Finish누르면 src/test/java안에 패키지가 생성되면서 해당클래스가 만들어진다.

package com.yk.yboard.control;

import static org.junit.Assert.*;
import org.junit.Test;

public class YboardControllerTest2 {
    @Test
    public void test() {
        fail("Not yet implemented");
    }
}

pom.xml에 Spring UNIT 테스트 모듈을 dependency에 등록해야 한다.

<!--  Spring JUNIT 테스트  -->
<dependency>
 <groupid>org.springframework</groupid>
 <artifactid>spring-test</artifactid>
 <version>${org.springframework-version}</version>
</dependency>

version에 spring버전에 해당되는 값을 세팅한다. (3.2.8) 이렇게 하게 프로젝트명을 오른쪽클릭 후 maven>Update Project..를 클릭하면 Maven Dependencies에 spring-test-.3.2.8.RELEASE.jar가 받아진다.
YboardControllerTest 클래스에 다음과 같이 애노테이션을 추가한다.

@RunWith(SpringJUnit4ClassRunner.class) : JUnit Test 클래스를 실행하기 위한 러너(Runner)를 명시적으로 지정한다.

또한 ApplicationContext.xml파일을 별도로 Test용도로 만들어서 가져오자.

왜냐하면 mybatis-config.xml에 설정된 xml파일경로가 웹경로이기때문에 TDD에서는 톰켓가동없이 테스트가 목적이므로 별도로 분리해주어야 하기 때문이다.

톰켓용 ApplicationContext.xml에 configLocation 변경

<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
  <property name="dataSource" ref="dataSource">
  <property name="configLocation" value="/WEB-INF/sql/mysql/mybatis-config.xml">            
</property></property></bean>

TDD용 ApplicationContext.xml configLocation 변경

<!-- 이부분은 원본과 다른 부분이다 -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
   <property name="dataSource" ref="dataSource">
   <property name="configLocation" value="file:src/main/webapp/WEB-INF/sql/mysql/mybatis-config.xml">
</property></property></bean>  

실제 파일경로가 표시되어 있다. 이부분만 빼고 나머지는 ApplicationContext.xml과 동일하다. 클래스에 다음을 추가한다.

@ContextConfiguration(locations = { "/applicationContext_test.xml" })

다음은 트랜젝션을 걸어서 처리한다.

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
@Transactional

defaultRollBack=true는 무조건 롤백이 된다. 데이터가 DB에 인서트된것을 확인하고자 하면 false로 해야 한다.

아래는 최종 클래스 소스이다.

@RunWith(SpringJUnit4ClassRunner.class)
// applicationContext_test.xml는 applicationContext.xml의 복사본이다.
// src/test/resource에 넣는다.
// 복사본을 만든 이유는 sqlSessionFactory에 mybatis-config.xml의 경로설정이 tomcat가동할때가 틀리기
// 때문이다.

@ContextConfiguration(locations = { "/applicationContext_test.xml" })
// defaultRollBack=true는 무조건 롤백이 된다. 데이터가 DB에 인서트된것을 확인하고자 하면 false로 해야 한다.
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
@Transactional
public class YboardControllerTest {
    @Autowired
    private YboardService yboardService;
    @Ignore
    @Test
    public void testViewYboard() {
        Map<string object=""> map = new HashMap<string object="">();
        map.put("boardID", 1);
        Yboard yboard = yboardService.viewYboard(map);
        assertEquals(yboard.getBoardID(), 1);
    }
}

이렇게 하면 TDD로 실제 DB 처리등을 테스트해볼수있다.

이것은 코드커버리지 100% TDD가 아니다. 따라서 DB입력, 조회등을 간단한 테스트용도로만 사용하고, Jenkins등에 maven 자동 테스트등으로 사용 해서는 안된다(입력/수정/삭제메소드가 있을 경우 실제 수행되기 때문이다) 따라서 다음과 같이 TDD 스킵이 되어야 한다(skipTests -> true)

<!-- TDD 스킵! -->
<plugin>
  <groupid>org.apache.maven.plugins</groupid>
  <artifactid>maven-surefire-plugin</artifactid>
  <version>2.15</version>
  <configuration>
    <skiptests>true</skiptests>
  </configuration>
</plugin>

아니면 사용하고나서 해당메소드에 @Ignore를 붙여도 된다.