[DBUnit] 테이블 데이터를 엑셀로 export

테스트

    @Test
    public void exportXls() throws Exception {
        dbUnitSupport.exportXlsFrom(“code”, “item”, “users”, “role”, “users_role”);
        assertTrue(new File(DBUnitSupport.EXPORTED_XLS_FILE).exists());
    }

구현

    protected void exportXlsFrom(String… tableNames) throws Exception {
        IDataSet dataSet = getConnection().createDataSet(tableNames);
        XlsDataSet.write(dataSet, new FileOutputStream(new File(EXPORTED_XLS_FILE)));
    }

흠.. 간단하네요. 간단 간단..

그런데. 테스트 할 때 생기는 파일들은 수동으로 지우기도 귀찮고.. 버전관리에 들어가면 더더욱 안 될 듯하고..
JUnit을 4.7로 올리고, @Rule 이라는 걸 써봐야겠습니다.

웹 통합 테스트 프레임워크 개발 중

웹 통합 테스트를 지시 받고, 몇일 전 삽질부터 시작해서 오늘까지 조금 열심히 달렸습니다. 오늘은 오후 6시쯤 되니까 머리가 아파서 더 못 앉아 있겠더군요. 아침에 오자마자 만들기 시작해서 조금 하다 보면 오후 1, 2시가 금방 되고, 그러면 밥 먹고 나서 또 조금 하다 보면 4, 5시가 되고, 또 조금 하다 보면 7, 8시가 되니까 하루가 정말 짧더군요. @_@

아직도 많이 손봐야 하지만, 이제 조금 윤곽이 잡혔습니다.

@RunWith(WebTestRunner.class)
@WarConfiguration(appName=”springsprout”)
@DataConfiguration(dataType=DataType.XML, location=”integration/sample/testData.xml”)
public class IndexPageWebTest {

    @WebTest
    public void sample(){
        WebDriver driver = new HtmlUnitDriver();
        driver.navigate().to(“http://localhost:8080/springsprout/index.do”);
        assertTrue(driver.getTitle().equals(“SpringSprout”));
    }

}

WebDriver를 이용한 초간단 웹 테스트 코드입니다. 이렇게 설정한 다음 테스트를 실행하면..
1. 현재 프로젝트를 WAR 패키징을 합니다.
2. 생성한 WAR를 테스트용 톰캣 서버에 springsprout 컨텍스트 패스로 배포합니다.(maven/tomcat6x/webapp/springsprout)
3. 배포가 잘 됐으면, 테스트 데이터를 넣어줍니다.
4. 이제 테스트를 실행합니다.
5. 테스트 데이터를 삭제합니다.
6. 앞서 배포한 WAR 파일을 undeploy 합니다.

여기서 4번에 해당하는 코드만 작성하면 됩니다. 나머지는 애노테이션만 붙여주면 되죠. 테스트 케이스 마다 서버를 켰다 껐다 하는 건 좀 무리고, WAR만 그때 그때 배포하도록 했습니다.

@RunWith(WebTestRunner.class)
@WarConfiguration(appName=”springsprout”)
@DataConfiguration(dataType=DataType.XML, location=”integration/sample/testData.xml”)
public class IndexPageWebTest {

    @WebTest
    public void test1(){
   
    }
   
    @WebTest
    public void test2(){
       
    }

}

이렇게 테스트를 하나 더 추가하면? WAR 배포 이후에 두 개의 테스트를 모두 실행한 다음에 WAR를 unploy합니다.

약간의 변화를 줄 수 있습니다. 테스트 데이터 입력이 필요 없다면, @DataConfiguration을 생략해도 됩니다. 그리고 테스트 서버 포트를 기본으로 8080을 사용하는데, 그 값을 @WarConfiguration의 port 속성에 줄 수 있습니다. 그럼 해당 포트에 배포를 시도하죠. 물론 그럴 때 해당 포트에 서버가 실행되고 있지 않다면, debug 모드의 로깅과 적절한 이름의 RuntimeException이 발생합니다.

꾸준히 가꿔야겠지만, 이제 내일 부터는 이녀석을 이용해서 본격적으로 웹 통합 CRUD 테스트를 만들고, CI를 해보려고 합니다.

얘 때문에 조금이라도 뒤적여 본 것들은 다음과 같습니다.
– JUnit 4.6
– Spring Test
– Cargo
– DBUnit
– WebDriver
– Maven Surefire Plugin
– Appfuse
– Maven Embedder

지난주 금, 월, 화, 수, 목.. 거의 일주일이네요.
개발이 참 더디고 어설프네요. ㅎㅎ 갈 길이 멀었습니다. @_@

DBUnit + Cargo + Webdriver를 이용한 웹 테스트 삽질 중

하려던 것은 간단합니다.

1. DBUnit으로 테스트 데이터를 넣고,
2. Cargo로 톰캣6를 돌리고
3. Webdriver로 HTML, IE, Firefox에서 CRUD+S(검색) 테스트를 하는 겁니다.

이게 되면 PageObject 패턴을 도입해서 테스트를 만들어 볼까 했는데, 아직 이 늪을 못 벗어나고 있습니다.

일단, Webdriver를 이용한 단독 테스트는 성공적이었습니다. 물론 아직 PageObject 패턴을 도입하진 않았었죠. 이 녀석이 해주는 일은 화면에 있는 정보를 쉽게 참조할 수 있게 도와주는 API를 제공해 주는 것입니다. 따라서 화면 테스트를 보다 쉽게 작성할 수 있곘죠. 그밖에 동일한 URI를 파이어폭스, 인터넷익스플로러, HTML, 사파리 드라이버를 이용하여 참조할 수 있어서 다기종 브라우저를 지원하는 자동화 테스트를 작성할 때 매우 유용할 것으로 보입니다.

Cargo는 서버를 조작할 수 있는 API를 제공하며, 여러 종류의 서버를 설정하고, WAR 파일을 배포하는 작업등을 할 수 있습니다. 자세히는 모릅니다. 매우 다양한 서버를 지원하며, 웹 테스트를 자동화 할 때 필수 도구로 보입니다. 또한 다양한 모드로 서버를 실행할 수가 있습니다.

DBUnit은 많이들 아실 것으로 생각하고 생략하겠습니다.

저는 먼저 Webdriver부터 실습해봤습니다. 홈페이지로 시작하기 같은 문서를 찾아서 살펴봤습니다. 그리고 바로 테스트를 작성해 봤습니다.

        WebDriver driver = new HtmlUnitDriver();
        driver.get(“http://localhost:8080/springsprout/index.do”);
        WebElement element = driver.findElement(By.linkText(“Login”));
        assertNotNull(element);
        assertEquals(“/login.do”, element.getAttribute(“href”));

음.. 잘 동작하네! API를 익혀야겠군…@_@ 이제 PageObject 패턴을 어떻게 도입해야 하나~

고민할 새도 없이 다음은 Cargo를 시작했습니다.

        Deployable war = new WAR(“target/springsprout.war”);
        LocalConfiguration configuration = new Tomcat6xStandaloneLocalConfiguration(“target/springsprout”);
        configuration.addDeployable(war);
        container = new Tomcat6xInstalledLocalContainer(configuration);
        container.setHome(“c:/apps/apache-tomcat-6.0.18”);
        container.start();

        container.stop();

이런식으로 서버를 동작 시킬 수 있었습니다. 저 … 안에 위에 작성한 웹 드라이버를 넣어보니 잘 동작했습니다. 문제는 이렇게 서버를 매번 올리고 내리는 작업을 테스트케이스마다 하면 굉장히 테스트가 오래 걸리고 비효율적이라는 겁니다. 따라서 이 작업은 반드시 Cargo 메이븐 플러긴을 이용해서 모든 테스트를 실행하기 전에 테스트 서버를 올렸다가 내리도록 해야겠습니다. 아직 해보진 않았습니다 @_@

일단 또 다시 고민할 새 없이 바로 DBUnit 까지 적용해 봤습니다.

    private void insertXMLData() throws IOException, DataSetException, DatabaseUnitException, SQLException {
        InputStream sourceStream = new ClassPathResource(“testData.xml”, getClass()).getInputStream();
        IDataSet dataset = new FlatXmlDataSet(sourceStream);
        DatabaseOperation operation = DatabaseOperation.CLEAN_INSERT;
        operation.execute(new DatabaseConnection(DataSourceUtils.getConnection(dataSource)), dataset);
    }

이런 메서드를 이용해서 testData.xml에 만들어 둔 테스트 데이터를 DB에 넣고 Cargo로 서버를 돌리고 Webdriver로 화면에 출력된 데이터를 검증하면 되리라 생각했습니다.

    @Test
    public void listMember() throws Exception {
        insertXMLData();
        assertEquals(2, memberRepository.getMemberList().size());

        Deployable war = new WAR(“target/springsprout.war”);
        LocalConfiguration configuration = new Tomcat6xStandaloneLocalConfiguration(“target/springsprout”);
        configuration.addDeployable(war);
        container = new Tomcat6xInstalledLocalContainer(configuration);
        container.setHome(“c:/apps/apache-tomcat-6.0.18”);
        container.start();

        WebDriver driver = new HtmlUnitDriver();
        driver.get(“http://localhost:8080/springsprout/member/list.do”);

        // logging
        System.out.println(driver.getTitle());
       assertEquals(2, memberRepository.getMemberList().size());
        System.out.println(driver.getPageSource());

        WebElement element = driver.findElement(By.linkText(“keesun@whiteship.me”));
        assertNotNull(element);
        element.getAttribute(“href”);
        container.stop();
    }

이런 식으로 말이죠. 하지만 결과는 참담했습니다. 분명히 빨간색 줄은 테스트가 assertion이 됩니다. Cargo로 서버도 잘 동작합니다. 하지만 WebDriver로 접근해 봤을 때 DB에 넣었던 데이터가 화면에 나와야 하는데 나오지 않습니다. sysout으로 HTML을 찍어 봤지만, 정말로 데이터가 없었습니다.

1. WAR로 배포한 애플리케이션과 테스트 코드가 다른 DB를 사용한다.

이런… 그렇치..mvn package로 묶었을 때 그 안에 들어가는 건 src에 있는 설정 파일이지 test가 아니니깐, 지금 test할 때 사용하는 DB랑은 다른 걸 쓸꺼 아냐 ㅠ.ㅠ 이런 바로.. 그럼 일단 src랑 test랑 같은 DB를 사용하게 설정해보자.(원래 이럼 안되는 건데..)

2. 같은 DB를 사용하지만 여전히 동일한 상황.

@_@ 뭐지.. 왜 이럴까? DBUnit이 데이터를 넣고 확인하는 DB와 서버가 참조하는 DB가 완전히 별개 인 것처럼 보이는데, 트랜잭션이 아예 달라서 그런건가. @_@ 어찌해야 되나.. 아 괴룹네요. 괴로워..

Why OSAF 1. 테스트 코드를 익힐 수 있습니다.

OSAF를 공개한지 한 달이 아직 안 됐습니다. 10월 23일에 공개했었죠. 지금까지 약 200에 가까운 다운로드를 기록하고 있지만, 전혀… 아무런… 반응이 없다는 것에는 가히 놀라울 뿐입니다. 그냥 제가 쓴 글의 댓글 몇 개 정도 뿐의 관심이 저에게 한 편으로는 아쉬움으로 또 다른 한 편으로는 오기로 다가옵니다.

완전 최첨단 프레임워크인 OSAF에 왜 이렇게 관심이 없을까. 고민을 많이 했습니다. 어렵나? 메이븐 떄문인가? 그거 없어도 되는데. 문서가 부족하긴 부족하고. 그래도 어떻게 이렇게 조용할 수가 있지. 홈피 디자인이 좀 구리긴 한데.. 그거 때문인가? ㅋ. OSAF 발음이 너무 어려운가? 별에 별 생각을 많이 했습니다. 당연히 기운도 빠집니다. OSAF를 공개한 건 어쩌면 OSAF에게 못씁짓을 한 건 아닌지 말이죠.(Max님의 ‘어디가서 밥은 먹고 다녀야 할텐데..’ 라는 댓글이 생각납니다.)

긍정적으로 생각하기로 했습니다. 언젠가는 빛을 보겠지. 열심히 계속 가꾸다 보면 언젠간 알아주겠지. 하고 말이죠. 그래서 OSAF가 여러분에게 어떤 도움을 줄 수 있을지 생각하고 알려드리기로 했습니다. 그 중 첫 번째가 바로 테스트 코드입니다.

OSAF의 테스트 커버리지는 60%가 조금 넘습니다. (앞으로 차차 올릴 예정입니다.) 60%의 테스트 커버리지는 전부 OSAF 개발팀에서 직접 작성한 테스트 코드입니다. 어딘가에서 배껴온 코드가 절대로 아닙니다. 테스트는 초기에 JUnit과 EasyMock을 사용해서 작성 했었습니다. 물론 스프링 테스트 기능도 사용하고 있죠. 배포 직전에는 EasyMock을 Mockito로 교체하여 비슷한 테스트를 보다 깔끔하고 직관적이며 적은 수의 코드로 대체할 수 있었습니다. DBUnit을 확장하여 OSAF가 제공하는 테스트 케이스를 이용하면 DAO 테스트가 매우 간편해질 것 입니다.

이렇게 좋은데… 한 번 들여다 보고 뭐라고 해주시지 않으시겠어요? 좋다. 잘했다. 고맙다. 이런거 말구요. 이 부분의 테스트는 이해가 안 된다. 테스트가 조금 이상하다. 이 부분의 테스트는 왜 안했냐. 어려워서 그런거냐? 이 부분의 테스트는 이렇게 고치는게 좋치 않겠냐? 이런.. 반응이 제가 가장 좋아하는 반응이자 OSAF에게 거름을 주는 방법입니다.

소스 코드는 굳이 다운 받지 않아도(장기적으론 받아 두시면 좋겠지만..)

http://www.opensprout.org:9060/browse/OSAF/osaf/trunk

위 링크로 가시면 웹에서 직접 볼 수 있습니다. 소스 코드나 OSAF 와 관련하여 문제나 제안하고 싶은 것이 있다면 주저하지 마시고 이슈를 등록해 주세요.

http://www.opensprout.org/jira/secure/Dashboard.jspa

8.1. DbUnit 사용하기

1. 먼저 DB에 입력할 dataset을 xml 형태로 작성 합니다.

이 때 주의 하실 점은 Entity와 Attribute의 이름들은 Object의 식별자를 사용하는 것이 아니라 Relation에서 사용되는 이름으로 사용해야 합니다.
[#M_ more.. | less.. |



<dataset>


       <k_group groupId=“1” name=“AJN” website=“http://agilejava.net” />


       <k_group groupId=“2” name=“OpenSeed” website=“http://agilejava.net” />


 


       <k_member memberId=“1” name=“keesun” email=“keesun@email.com” city=서울/>


       <k_member memberId=“2” name=“parsdozz” email=“parsdozz@email.com” city=서울/>


       <k_member memberId=“3” name=“seal” email=“seal@email.com” city=대전/>


 


       <k_membergroup memberGroupId=“1” memberId=“1” groupId=“1” role=“O”/>


       <k_membergroup memberGroupId=“2” memberId=“1” groupId=“2” role=“M”/>


       <k_membergroup memberGroupId=“3” memberId=“2” groupId=“2” role=“M”/>


       <k_membergroup memberGroupId=“4” memberId=“3” groupId=“2” role=“A”/>


 


       <k_messenger messengerId=“1” memberId=“1” m_type=“M” m_id=“keesun@msn.com”/>


       <k_messenger messengerId=“2” memberId=“1” m_type=“S” m_id=“keesun”/>


       <k_messenger messengerId=“3” memberId=“2” m_type=“M” m_id=“paradozz@msn.com”/>


       <k_messenger messengerId=“4” memberId=“3” m_type=“S” m_id=“seal”/>


</dataset>

_M#]


2. 입력한 샘플 데이타를 테스트할 메소드를 만들고 DbUnit을 사용하여 DB에 넣습니다.




public void testWithSampleData() throws Exception{


     insertFlatXmlDataSet(“test/src/keesun/kSampleData.xml”);


}


이상태에서 test를 돌려보고 DbUnit이 동작하는데 이상은 없는지 확인합니다. 만약 위에서 작성한 xml에 매칭되는 컬럼을 못찾을 경우 에러가 발생합니다.

3. 입력한 샘플을 기반으로 간단한 쿼리를 날려서 결과를 확인해 봅니다.



public void testWithSampleData() throws Exception{


      insertFlatXmlDataSet(“test/src/keesun/kSampleData.xml”);


 


      assertEquals(3, kMemberDao.getAll().size());


      assertEquals(2, kGroupDao.getAll().size());


      assertEquals(4, kMemberGroupDao.getAll().size());


      assertEquals(4, kMessengerDao.getAll().size());


}


테스트는 통과 합니다~ 🙂
좀더 복잡한 쿼리를 날리기 위해서는 HQL과 Criteria를 공부해야 합니다. 하지만 그다지 어렵지 않다는거~

사용자 삽입 이미지