Top / Java / jcoverage

概要

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

コードカバレッジツールにもいろいろ方式があるのですが、このjcoverageは

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

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

basic.png

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

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

ダウンロード

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

基礎

準備

まずは基礎の基礎から。しつこいですが、ポイントはコンパイル後、Antタスクなどでデバッグコード埋め込みをしているというところです。つまりコンパイルまでは今までと同じ*1で、そのクラスファイルを動かすのではなくて、デバッグを埋め込んだあとのコードを動かす、ということですね。

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

01.png

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

antタスクの作成

jcoverageにはAntタスクが付属しています。使用するのは主に

instrument
デバッグコードをクラスに埋め込むときに使います。
report
出力された収集結果ファイル(jcoverage.ser)からレポート(html他)を出力します。
merge
複数の結果ファイルをマージしてひとつのファイルにします*2

です。

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

  • クラスパス設定
      <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>

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

result01.png

カバレッジの一覧

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の注意点

こんな障害に巻き込まれました。

  • EclipseからAntでJunitを実行するとき、jarがねえって怒られることがあったので[ウィンドウ]>[設定]>[Ant]>[ランタイム]のグローバル項目に、junit.jarを追加した。環境によっては、他のjarとかもパスを通す必要があった。とくにJDK1.3系の場合はXML関連がないとエラーになるので、ココで追加した。プロンプトでやる場合は、${ANT_HOME}/libに入れとけばいいのかな?
  • Antでコンパイル&InstrumentしたクラスをJunitで実行しようとするとエラーになる。
    • コンパイルするコンパイラのバージョンと実行時のJREのバージョンの不整合が問題になるときがあるようです。稼動実績はコンパイル時、ランタイム時ともにJRE1.3。。。*3
  • うえには書きませんでしたが、JUnitタスクを実行すると、html生成(Xalan使ってXML->html変換)でコケてる。あーうまくいかねぇ。コマンドプロンプトから、J2SDK1.4.2.08ならすべてOKでした!!いろいろ組み合わせでトラブルなぁ。

Servletなどサーバサイド、J2EE環境で使う。

疲れました。。。また書きます。

関連リンク


この記事は

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

Top / Java / jcoverage

現在のアクセス:43539


*1 Antで一緒にやっちゃってももちろんよい
*2 サーバサイドのときには必ず使う。後述
*3 実はRADでやってるからこんなになっちゃうのかな?。こんなので、ホントにつかえんのか???

添付ファイル: filebuild.properties 3641件 [詳細] filebuild.xml 3944件 [詳細] fileresult01.png 2404件 [詳細] fileresult02.png 2360件 [詳細] file01.png 2480件 [詳細] filebasic.png 2658件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2021-04-19 (月) 10:16:55 (1104d)