Whiteship's Note

[회사일] DAO 테스트 만들기

프로젝트/SLT : 2010.06.01 18:55


이전 코드에서는 뭐 테스트 해보고 싶을 만한게 없었다. 사실 하두 자주 써먹었고 거의 API를 그대로 쓴 코드라서 테스트 하지 않아도 확신이 서는 코드가 대부분이었다. 그 중에서도 굳이 가장 불안한 코드를 꼽으라면 DAO 코드가 되겠다. 나머진 그냥 단순 위임이라 뭐 의심할께 없다.

DAO 코드를 보자.

    public List<Code> list() {
        return getCriteriaOf(Code.class).list();
    }

흠.. 테스트 할 맛이 안난다.

   private Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    private Criteria getCriteriaOf(Class clazz){
        return getSession().createCriteria(clazz);
    }

이런 private 메서드를 쓰고 있지만 전혀 테스트 할만한 뭐시기가 감지되지 않는다.

list 사이즈를 구하는 메서드를 만들어 보기로 했다. 페이징을 구현할텐데 거기서 분명히 전체 목록 크기를 구하는 쿼리가 필요할 것이기 떄문이다.

CodeDao 인터페이스에 코드를 추가하자.

    int totalSize();

다음은 이것을 구현한다.

    public int totalSize() {
        return (Integer)getCriteriaOf(Code.class)
            .setProjection(Projections.count("id"))
            .uniqueResult();
    }

오.. 제법 낯선 코드를 두 중 정도 코딩했다. 왠지 쬐끔 불안하다. 쬐금.. API 학습 차원에서 테스트를 해봐야겠단 생각이 든다. 좋아 결심했어.

소스 코드와 동일한 패키지에 CodeDaoImpleTest라는 테스트를 만든다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/testContext.xml")
@Transactional
public class CodeDaoImplTest extends DBUnitSupport {

    @Autowired CodeDao codeDao;

    @Test
    public void testTotalSize() throws Exception {
        insertXmlData("testData.xml");
        assertThat(codeDao.totalSize(), is(1));
    }

}

여기서 주목할 것은 굵게 표시한 부분이다. 먼저 테스트에서 사용할 DB가 운영 DB와 같으면 테스트 데이터를 넣고 확인할 때 문제가 될 수 있으니 전혀 다른 DB 설정을 보도록 테스트용 애플리케이션 컨텍스트와 데이터베이스 프로퍼티 파일을 만든다.

    <context:property-placeholder location="classpath*:test.database.properties"/>

이 부분 빼곤 나머진 같다.

database.password=
database.username=sa
database.url=jdbc:hsqldb:mem:ㅇㅇㅇ
database.driverClassName=org.hsqldb.jdbcDriver
hibernate.dialect=org.hibernate.dialect.HSQLDialect

다음은 DBUnit을 사용하기 쉽게 해주는 DBUnitSupport 클래스다. DataSource를 필요로 하기 때문에 자동 주입 받도록 설정한다.

public class DBUnitSupport {

enum DataType {EXCEL, FLATXML}

@Autowired
private DataSource dataSource;

protected void cleanInsertXmlData(String fileSource) throws Exception {
insertData(fileSource, DataType.FLATXML, DatabaseOperation.CLEAN_INSERT);
}
protected void cleanInsertXlsData(String fileSource) throws Exception {
insertData(fileSource, DataType.EXCEL, DatabaseOperation.CLEAN_INSERT);
}

private void insertData(String fileSource, DataType type, DatabaseOperation operation) throws Exception {
InputStream sourceStream = new ClassPathResource(fileSource, getClass()).getInputStream();

IDataSet dataset = null;
if (type == DataType.EXCEL) {
dataset = new XlsDataSet(sourceStream);
}
else if (type == DataType.FLATXML) {
dataset = new FlatXmlDataSet(sourceStream);
}

operation.execute(
new DatabaseConnection(DataSourceUtils.getConnection(dataSource)), dataset);
}

protected void insertXmlData(String fileSource) throws Exception {
insertData(fileSource, DataType.FLATXML, DatabaseOperation.INSERT);
}

protected void insertXlsData(String fileSource) throws Exception {
insertData(fileSource, DataType.EXCEL, DatabaseOperation.INSERT);
}

}

DataSource가 필요하기 때문에 
나머지 코드에 대한 설명은 생략~

<dataset>
<code id="1" name="블랙" code="BLK" />
</dataset>

테스트는 성공한다.

자 이제 DaoTest라는 클래스를 만들어서 설정을 옮겨보자.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/testContext.xml")
@Transactional
public class DaoTest extends DBUnitSupport {
}

참고로 이 클래스를 src 밑에서 만들었다면 컴파일 에러가 난다.

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>org.springframework.test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

여기서 스코프를 test라고 했기 때문이다. 지워준다. 프레임워크성 코드가 생기기 시작하기 때문에 패키징을 조금 신경써서 나눠둔다.

public class CodeDaoImplTest extends DaoTest {

    @Autowired CodeDao codeDao;

    @Test
    public void testTotalSize() throws Exception {
        insertXmlData("testData.xml");
        assertThat(codeDao.totalSize(), is(1));
    }
}

자. CodeDaoImplTest가 깔끔해졌다. 앞으로 DAO 테스트를 할 땐 이렇게 DaoTest만 확장해서 만들면 되겠다.






top

Write a comment.




: 1 : ··· : 23 : 24 : 25 : 26 : 27 : 28 : 29 : 30 :