#author("2021-04-19T01:16:55+00:00","","")
#topicpath
----
//ここにコンテンツを記述します。
#contents

***概要 [#t7940701]

[[jcoverage:http://www.jcoverage.com/]]とは、単体テスト実施時のコードの網羅率など、いわゆるカバレッジを計測するためのツールです。

コードカバレッジツールにもいろいろ方式があるのですが、このjcoverageは
-Antタスクなどで、バイトコード(クラスファイル)に対してカバレッジを収集するデバッグを埋め込み、
-コードが稼動すると、埋め込まれたデバッグプログラムがファイルに収集内容を出力し、
-Antタスクなどで、そのファイルを元にカバレッジなどを色分けしてレポーティング(html出力など)する

といった方式になっています。よってJUnitで単体テストを実施するときに、元のクラスではなくデバッグを埋め込まれたコードを用いてテスト実施をすることによって、単体テスト実施時のテストの網羅率などを計測することができます。


#ref(basic.png)


似たようなツールとして、CoberturaやCloverがあるのですが、CoberturaはJDK1.4以上しか動かないっぽい、Cloverはフリーでない、ということを鑑みてとりあえずjcoverageを使ってみました。

このようなツールって、クライアント環境だけならエイヤでやって動くもんなんですけど、サーバサイドだと結構手順がめんどくさいです。。つまりjcoverage,Junit,Cactus,WEBコンテナ,Eclipseなどの開発ツール、を連携させるのがやたらめんどくさい。
で、ようやく動かしかたぼんやりとではあるのですがわかってきたので、メモっておきます。


***ダウンロード [#df0b7b73]
http://www.jcoverage.com/gpl-license.html よりダウンロード可能です。GPLとそうでない用があるみたいで、GPL版がこのさきどんなメンテナンスをされていくのかはよくわかりませんが、とりあえずGPL版をダウンロードします。


**基礎 [#a74f2435]
***準備 [#qbea4e71]
まずは基礎の基礎から。しつこいですが、ポイントはコンパイル後、Antタスクなどでデバッグコード埋め込みをしているというところです。つまりコンパイルまでは今までと同じ((Antで一緒にやっちゃってももちろんよい))で、そのクラスファイルを動かすのではなくて、デバッグを埋め込んだあとのコードを動かす、ということですね。

やってみます。適当にEclipseでプロジェクトを作成します。そのプロジェクトにダウンロードしてきたファイルを配置して、クラスパスを通しておきます。また、テスト対象クラスとテストケースクラスを作成して下図のように配置しておきます。

#ref(01.png)

とりあえずここまでで、Eclipse上からJunitを起動することができます。

***antタスクの作成 [#y27e5aa2]
jcoverageにはAntタスクが付属しています。使用するのは主に
:instrument|デバッグコードをクラスに埋め込むときに使います。
:report|出力された収集結果ファイル(jcoverage.ser)からレポート(html他)を出力します。
:merge|複数の結果ファイルをマージしてひとつのファイルにします((サーバサイドのときには必ず使う。後述))

です。

全てAntでやる場合は、ソースコードのコンパイル -> instrumentタスクの実行 -> Junitの実行 -> レポーティング となるわけですね。そのようなbuild.xmlを以下に添付します。

#ref(build.xml)
#ref(build.properties)

-クラスパス設定
   <path id="project.class.path">
     <pathelement path="${class.dir}" />
     <fileset dir="${jar.dir}">
       <include name="**/*.jar" />
     </fileset>
   </path>

-タスク定義
   <taskdef classpathref="project.class.path" resource="tasks.properties" />

-テスト対象のコンパイル
   <target name="javac.src" depends="init" description="ソースをビルドします">
     <mkdir dir="${class.dir}" />
     <!-- リソースファイルなどをコピーしている -->
     <copy todir="${class.dir}" preservelastmodified="yes">
       <fileset dir="${src.dir}">
         <include name="**" />
         <exclude name="**/**.java" />
       </fileset>
     </copy>
     
     <javac srcdir="${src.dir}" destdir="${class.dir}" encoding="${compile.encoding}" includeantruntime="no" 
      memoryInitialSize="256M" fork="yes" memoryMaximumSize="256M" includes="**" debug="true">
       <classpath refid="project.class.path" />
     </javac>
   </target>

-テストクラスのコンパイル
   <target name="test.javac" depends="javac.src" description="テスト用ソースをビルドします">
     <mkdir dir="${class.dir}" />
     <!-- リソースファイルなどをコピーしている -->
     <copy todir="${class.dir}" preservelastmodified="yes">
       <fileset dir="${test.src.dir}">
         <include name="**" />
         <exclude name="**/**.java" />
       </fileset>
     </copy>
 
     <javac srcdir="${test.src.dir}" destdir="${class.dir}" encoding="${compile.encoding}" 
       memoryInitialSize="256M" fork="yes" memoryMaximumSize="256M" debug="true">
       <classpath refid="project.class.path" />
     </javac>
   </target>

-デバッグコードの埋め込み 
   <target name="instrument" description="Add jcoverage instrumentation">
     <instrument todir="${build.instrumented.dir}">
       <ignore regex="org.apache.log4j.*" />
       <fileset dir="${class.dir}">
         <include name="**/*.class" />
       </fileset>
       <classpath refid="project.class.path" />
     </instrument>
 
     <!-- リソースファイルなどをコピーしている -->
     <copy todir="${build.instrumented.dir}" preservelastmodified="yes">
       <fileset dir="${class.dir}">
         <include name="**" />
         <exclude name="**/*.class" />
       </fileset>
     </copy>
 
     <!-- 一端クラスディレクトリを消して -->
     <delete dir="${class.dir}" />
     <mkdir dir="${class.dir}" />
     <!-- デバッグ込みクラスファイルをコピー -->
     <copy todir="${class.dir}" preservelastmodified="yes">
       <fileset dir="${build.instrumented.dir}">
         <include name="**" />
       </fileset>
     </copy>
   </target>

ここまででとりあえず実行してみます。Eclipse上からAntを実行しました。実行した内容は
 ant clean javac instrument
です。実行結果は以下のようになりました。
 Buildfile: d:\xxxxxx\JCoverageClient\build.xml
 init:
      [echo] Apache Ant version 1.6.2 compiled on July 16 2004
      [echo] Java ver. 1.3
      [echo] JCoverageTest
      [echo] BaseDir: D:\xxxxxx\JCoverageClient
      [echo] 日付:2005/09/03
 clean:
    [delete] Deleting directory D:\xxxxxx\JCoverageClient\classes
    [delete] Deleting directory D:\xxxxxx\JCoverageClient\instrumented-classes
    [delete] Deleting directory D:\xxxxxx\JCoverageClient\document\JCoverageClient
 javac.src:
     [mkdir] Created dir: D:\xxxxxx\JCoverageClient\classes
      [copy] Copied 1 empty directory to 1 empty directory under D:\xxxxxx\JCoverageClient\classes
     [javac] Compiling 1 source file to D:\xxxxxx\JCoverageClient\classes
 test.javac:
     [javac] Compiling 1 source file to D:\xxxxxx\JCoverageClient\classes
 javac:
 instrument:
 [instrument] jcoverage 1.0.5 copyright (c)2003 jcoverage ltd. http://jcoverage.com/
 [instrument] jcoverage is licensed under the GNU General Public License
 [instrument] jcoverage comes with ABSOLUTELY NO WARRANTY
 [instrument] instrumenting 2 classes to D:\xxxxxx\JCoverageClient\instrumented-classes
    [delete] Deleting directory D:\xxxxxx\JCoverageClient\classes
     [mkdir] Created dir: D:\xxxxxx\JCoverageClient\classes
      [copy] Copying 2 files to D:\xxxxxx\JCoverageClient\classes
 BUILD SUCCESSFUL
 Total time: 6 seconds

-EclipseからJUにtJUnitを実行

Antで実行するタスクもあるのですが、とりあえず、Eclipseから実行。。


-テストを実行した後のレポーティング
   <target name="coverage" description="HTML and XML coverage reports can be found in build/coverage">
     <report srcdir="${src.dir}" destdir="${build.coverage.dir}">
       <classpath refid="project.class.path" />
     </report>
     <report srcdir="${src.dir}" destdir="${build.coverage.dir}" format="xml">
       <classpath refid="project.class.path" />
     </report>
   </target>

以上で完成です。実行結果は以下のようになりました。

#ref(result01.png)
カバレッジの一覧


#ref(result02.png)
詳細


ちなみに、テスト対象のクラスとテストクラスは以下の通り。
-Hoge.java
 /*******************************************************************************
  * Copyright (c) 2005 Masatomi KINO.
  * All rights reserved. 
  * $Id$
  *******************************************************************************/
 //作成日: 2005/09/03
 package kino;
 
 /**
  * @author Masatomi KINO
  * @version $Revision$
  */
 public class Hoge {
     /**
      * どうでもいいロジック。引数両方0なら50を返す。
      *  aだけ0ならbを100倍して返す。 それ以外は足して返す。
      * 
      * @param a
      * @param b
      * @return
      */
     public int add(int a, int b) {
         if (a == 0 && b == 0) {
             return 50;
         } else if (a == 0) {
             return b * 100;
         }
         return a + b;
     }
 
 }


-HogeTest.java
 /*******************************************************************************
  * Copyright (c) 2005 Masatomi KINO.
  * All rights reserved. 
  * $Id$
  *******************************************************************************/
 //作成日: 2005/09/03
 package kino;
 
 import junit.framework.TestCase;
 
 /**
  * @author Masatomi KINO
  * @version $Revision$
  */
 public class HogeTest extends TestCase {
 
     private Hoge hoge;
 
     public static void main(String[] args) {
         junit.textui.TestRunner.run(HogeTest.class);
     }
 
     /*
      * @see TestCase#setUp()
      */
     protected void setUp() throws Exception {
         super.setUp();
     }
 
     /*
      * @see TestCase#tearDown()
      */
     protected void tearDown() throws Exception {
         super.tearDown();
     }
 
     public final void testAdd() {
         hoge = new Hoge();
         assertEquals(10000, hoge.add(0, 100));
         assertEquals(200, hoge.add(100, 100));
         //        assertEquals(50, hoge.add(0,0));
 
     }
 
 }


***Antの注意点 [#b21c0c47]
こんな障害に巻き込まれました。
-EclipseからAntでJunitを実行するとき、jarがねえって怒られることがあったので[ウィンドウ]>[設定]>[Ant]>[ランタイム]のグローバル項目に、junit.jarを追加した。環境によっては、他のjarとかもパスを通す必要があった。とくにJDK1.3系の場合はXML関連がないとエラーになるので、ココで追加した。プロンプトでやる場合は、${ANT_HOME}/libに入れとけばいいのかな?

-Antでコンパイル&InstrumentしたクラスをJunitで実行しようとするとエラーになる。
--コンパイルするコンパイラのバージョンと実行時のJREのバージョンの不整合が問題になるときがあるようです。稼動実績はコンパイル時、ランタイム時ともにJRE1.3。。。((実はRADでやってるからこんなになっちゃうのかな?。こんなので、ホントにつかえんのか???))

-うえには書きませんでしたが、JUnitタスクを実行すると、html生成(Xalan使ってXML->html変換)でコケてる。あーうまくいかねぇ。コマンドプロンプトから、J2SDK1.4.2.08ならすべてOKでした!!いろいろ組み合わせでトラブルなぁ。

**Servletなどサーバサイド、J2EE環境で使う。 [#k3738780]
[[疲れました。。。また書きます。>Java/jcoverage/ServletなどJ2EE環境で使う。]]


**関連リンク [#r33cad0f]
#ls2
-[[djUnit:http://eclipsewiki.net/eclipse/?djUnit]]


----
この記事は
#vote(おもしろかった[20],そうでもない[2])
#vote(おもしろかった[21],そうでもない[2])
- Thank you for your job!! -- [[Helen]] &new{2007-09-20 (木) 19:36:07};
- 気づいたら変な行(コメント行等)に未実行のマーカーがついてしまいました。特定のクラスのカバレッジ結果のみjcoverage.serから削除することは可能でしょうか? -- [[jun]] &new{2007-12-26 (水) 18:56:13};

#comment
#topicpath


SIZE(10){現在のアクセス:&counter;}

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS