JUnit4 기반의 테스트케이스와 Clover 를 함께 쓰기위한 ant 설정 by 오리대마왕

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>