Clover + Ant 사용하기
clover는 junit, testNG 등의 자동화 unit test 도구를 통해 수행된 unit test에 대한 코드 coverage 측정을 해 주는 꽤 유명한 도구이다. 비슷한 기능을 하는 emma, cobertura 와 같은 무료 도구들도 있긴 하지만, 하여간 현 프로젝트에서는 [clover]를 사용하고 있다. 뭐가 더 나은지는 딱히 비교를 해 보지 않아서 모르겠다.
clover는 IDE의 plug-in 혹은 ant task,maven 으로 제공된다. 예전 eclipse의 plug-in 으로 사용해 본 경험으로는, ant task로 독립적으로 수행하는 것이 더 깔끔하였다. 이유는, clover와 같은 도구는 어떤 코드가 어떤 test를 통해 수행되었는지를 측정하기 위해 compile에 앞서 instrumentaion 이라는 작업을 거치는데, 이것은 소스코드를 변경하여 새로운 클래스들을 생성하기 때문이다. plug-in으로 수행하게 되면 원래의 코드와 instrumentation 된 코드가 뒤섞여 관리가 힘들었다. 또한 구동 자체가 느려지는 감이 있어서 개발하는데 조금 귀찮아지는 면이 있었다. 내가 겪은 더 큰 문제는 eclipse가 종종 죽어버리는 것이었다.
coverage 측정이라는 것이 매 단위 테스트마다 실행할 필요도 없고, cruisecontrol 등과 함께 돌려서 하루에 한번 정도만 확인하면 되는 녀석이니 plug-in 으로 괜히 개발에 부담을 주는 것 보다는 ant 로 깔끔하게 분리를 하는 것이 훨씬 편리하였다.
일반적인 Junit 3.8 환경
우리 프로젝트에서는 초기에는 junit 3.8 기반으로 테스트를 돌렸다. src/test 밑에 junit test class들을 넣었고, test class 들은 XXXTest.testAAA() 형태의 class명과 method명을 가지도록 규칙을 정하였다. 이 경우, clover는 별다른 설정 없이 기본 설정으로 잘 수행이 되었고, report에서도 어느 test를 통해 어느 line 이 수행되었는지 잘 보여줬다. 대략 다음과 같이 설정하였다. 물론, 실전에서 쓸 때는 일일이 target 을 잘라주어 정의하는 것이 좋다.
<target name="do_clover">
<!-- clover 설정 부분 -->
<clover-setup enable="true">
<files>
</files>
</clover-setup>
<!-- compile 부분 : clover-setup enabled 되었기 때문에 compile 되는 코드들은 instrumented 된 코드임 -->
<javac ... >
<!-- junit 실행. 이때 결과를 xml 로 남겨야 clover 에서 결과까지 참조할 수 있다. 자세한 것은 ant manual 참고한다. -->
<junit showoutput="true" dir="." fork="true" forkmode="perTest" filtertrace="false" errorproperty="true">
<batchtest todir="${junit.output}" >
<fileset dir="${src.test}">
<include name="**/*.java"/>
</fileset>
</batchtest>
</junit>
<!-- 실행된 junit 결과를 기반으로 레포트 생성 -->
<clover-historypoint historyDir="${clover.output.history}"/>
<clover-html-report outdir="${clover.output}" historyDir="${clover.output.history}" testresultsdir="${junit.output}"/>
<!-- clover 설정을 지워서 clean 한 code 로 재 build -->
<clover-setup enable="false"/>
<javac ... >
</target>
Junit 4 환경
프로젝트 중간에, Junit 을 3.8 에서 4.4 버전으로 변경하였다. 이때부터 clover 가 testcase 를 인식하지 못했다. 이 경우에도 coverage 는 잘 보이는데, 어떤 test로 인해 수행되었는지, test 결과는 어떠했는지 알 수가 없다. clover를 이용해 coverage만 보고자 하는 경우에는 아무 상관이 없지만, 사람 마음이 또 안그렇잖아. 기왕 제공해 주는 기능, 제대로 써 먹어보자. 다른 부분은 그대로 유지하고, clover-setup 부분만 좀 더 정교화 하면 된다.
<clover-setup enabled="true">
<fileset dir="${src.test}"/>
<fileset dir="${src.main}"/>
<!-- junit 3.8 일때는 testsources 를 설정하지 않아도 잘 되었지만, 이제는 일일이 해 줘야 한다. -->
<testsources dir="${src.test}">
<!-- testcase package에 대한 정규식 표현 -->
<testclass package="com.mywork.test.*">
<!-- junit 4 에서는 test method 에 대해 @Test 를 사용하니 이렇게 해 주자 -->
<testmethod annotation="Test"/>
</testclass>
</testsources>
</clover-setup>
나머지 부분은 3.8 환경과 동일하다. 이렇게 해 주면 3.8 쓸 때와 동일하게, 제대로 test case를 인식한다.
Junit 3.8 + Junit 4 가 혼재된 환경
앞서 이야기 했듯이, 프로젝트 중간에 환경이 바뀌어서 예전에 만든 test는 3.8 , 새로 만든 test는 4 기반이다. 이렇게 되어도 junit 4 버전은 하위호환성을 지니기 때문에 실행에는 문제가 없지만, 위의 clover 설정대로 할 경우 둘 중 하나만 인식을 하게 된다. 이 경우, 위의 clover-setup 부분의 testsources 부분만 정교화 해 주면 된다. 우리 프로젝트의 경우 4 대는 따로 junit 이라는 패키지명을 부여했기 때문에 3.8 기반 test와 4.x 기반 test는 서로 다른 패키지에 위치하였다. 그래서 다음과 같이 설정하였다.
<testsources dir="${src.test}">
<!-- 2가지 junit test 모두 포함해야 하므로 or 로 묶어줌 -->
<or>
<!-- junit 4 를 위한 설정 -->
<testclass package="com\.mywork\.junit.+">
<testmethod annotation="Test"/>
</testclass>
<!-- junit 3.8 을 위한 설정 : 3.8 에서는 test method 는 무조건 testXXX 로 시작해야 하므로 이를 적용함 -->
<testclass package="com\.mywork\.test.*">
<testmethod name="test.+"/>
</testclass>
</or>
</testsources>
부록: 불필요한 resource를 제외하고 싶은 경우
자, 이제 junit test들은 모두 제대로 등록이 된 상태이다. 여기에 조금 더 욕심을 부리자면, 불필요한 resource를 clover 에서 배제하여 실제 사용하는 코드에 대해서만 coverage 를 측정해보자. 우리 프로젝트의 경우 코드 자동 생성 도구를 이용해서 생성된 불필요한 코드가 섞여 있다. 이 코드들 때문에 coverage가 낮게 측정되는 경향이 있는데, 이들을 제거하여 조금이라도 coverage를 늘려보자(이히히히). 이 부분은, clover-setup 에서 대상을 정의하는 부분에서 설정하면 된다.
<clover-setup enabled="true">
<!-- 일단 test, main 코드들 위치를 설정한다. -->
<fileset dir="${src.test}"/>
<fileset dir="${src.main}"/>
<!-- clover에서 배제할 resource를 설정한다. 정의 방법은 ant 의 fileset 형식과 같...은 것 같다. -->
<files>
<exclude name="**/auto_generated/**/*.java"/>
</files>
</clover-setup>




덧글