Top / Java / jcoverage / ServletなどJ2EE環境で使う。

クライアントサイドのjcoverageに関しては何とか動いたようです。いよいよサーバサイドのカバレッジ計測をやってみようと思います。確認は以下のような環境で行いました。

プロダクトバージョン役割
WebSphereWebSphere 5.0.2テスト環境*1WEBコンテナ
Cactus1.7.1サーバサイドテスティングフレームワーク
Junit3.8.1テスティングフレームワーク
jcoverage1.0.5カバレッジツール

Cactusとはサーバサイドのテスティングフレームワークです。JUnitのクラスを拡張して、WEBコンテナ上でテストを行うためのクラス群を提供します。

具体的には、requestパラメータにいろいろな値をセットしてブラウザのリクエストをシミュレーションすることや、ブラウザへ返却される画面に正しく値がセットされてるかをチェックするクラスなどを提供してくれます。

さて、前回にJUnitとの連携まではやりましたが、今回がいままでと違うところはWEBコンテナ上で稼働する箇所とクライアントで稼働する箇所があるというところです。つまりリクエスト情報を構築してリクエストを放るまではクライアント側のJavaVM,リクエストを受けて処理をしてクライアントに返すまではWEBコンテナ上のJavaVM、という方式になります。クライアント側のカバレッジ計測についてはある意味いままでと変わらないのですが、WEBコンテナで稼働する部分のカバレッジ計測をどうするかというところがポイントになります。いろいろ調べた結果、以下のようなやり方でやればよい(ような気がする)事がわかりました。

  • クライアント側はクライアント側で、コンテナ側はコンテナ側でそれぞれ計測して、マージする
  • 計測するにはデバッグ埋め込み済みのコードをデプロイする必要がある
  • (特にWASだけかも?)WEBコンテナにjcoverageのjarをパスを通して認識させておく

難しいのは、デプロイするearにアーカイブされるクラスにどのようにデバッグを埋め込むか、ですね。通常開発環境でのコーディング・テストフェーズでは、自分でアーカイブを作ることはせず、開発環境が勝手にデプロイしてくれることが多いからです*2。これに関してはclassesにデバッグ埋め込み済みのコードを配置するようビルドする、ことで解決できそうです。

result.png

さて例でやってみます。

準備

WebSphereのテスト環境でjcoverageを使うときにサーバ側でエラーが発生してしまうようで、

WebSphereテスト環境 >> 環境 >> WebSphere特定クラスパス

でjcoverage.jarを追加する必要があるみたいです。Tomcatなどでやるときもcommon/libとかに入れておく必要があるのかな?

serversettiong.png

手順

手順は、

  • Eclipseでコンパイル
  • AntでInstrument
  • WEBコンテナ起動
  • EclipseでCactus起動
  • Antでレポート

となります。ポイントはデフォルトではclassesがクラスパスに設定されてしまうので、instrumentしたファイルがclassesに配置されるようビルドするって事です。あと、Eclipseは自動的にビルドする機能がありますが、そうするとせっかくInstrumentしたファイルを上書きしてしまうので、自動ビルドをOFFにしておきました。

プロジェクト作成

プロジェクト名はJCoverageTestWeb?としました。CVSはこちら

Eclipseでコンパイル

今回はAntではなくEclipse上のビルドを用いました。Antでやる場合はこんな感じ。

<!-- 環境依存ファイルの読み込み-->
<!-- 実際にファイルを参照してみてください -->
<property file="build.win.properties" />
<property file="build.properties" />

<!-- クラスパス -->
<path id="project.class.path">
  <pathelement location="${j2ee.jar}" />
  <pathelement path="${document.root}/${class.dir}" />
  <fileset dir="${document.root}/${jar.dir}">
  <include name="**/*.jar" />
  </fileset>
</path>
<!-- クラスパス名の定義 以上 -->

<taskdef classpathref="project.class.path" resource="tasks.properties" />

<target name="init">
  <tstamp>
  <format property="TODAY" pattern="yyyy/MM/dd" />
  </tstamp>
  <filter token="project.name" value="${ant.project.name}" />
  <echo>${ant.version}</echo>
  <echo>Java ver. ${ant.java.version}</echo>
  <echo>${ant.project.name}</echo>
  <echo>BaseDir: ${basedir}</echo>
  <echo>日付:${TODAY}</echo>
</target>


<!-- コンパイル -->
<target name="javac.src" depends="init" description="ソースをビルドします">
  <mkdir dir="${document.root}/${class.dir}" />
  <copy todir="${document.root}/${class.dir}" preservelastmodified="yes">
  <fileset dir="${src.dir}">
  <include name="**" />
  <exclude name="**/**.java" />
  </fileset>
  </copy>
  <javac srcdir="${src.dir}" destdir="${document.root}/${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="${document.root}/${class.dir}" />
  <copy todir="${document.root}/${class.dir}" preservelastmodified="yes">
  <fileset dir="${test.src.dir}">
  <include name="**" />
  <exclude name="**/**.java" />
  </fileset>
  </copy>
  <javac srcdir="${test.src.dir}" destdir="${document.root}/${class.dir}" 
    encoding="${compile.encoding}" 
    memoryInitialSize="256M" fork="yes" memoryMaximumSize="256M" debug="true">
  <classpath refid="project.class.path" />
  </javac>
</target>

AntでInstrument

Instrumentはクライアント環境だけの場合もほとんど同じ。

<target name="instrument" description="Add jcoverage instrumentation">
<instrument todir="${document.root}/${class.instrumented.dir}">
<ignore regex="org.apache.log4j.*" />
<fileset dir="${document.root}/${class.dir}">
  <include name="**/*.class" />
</fileset>
<classpath refid="project.class.path" />
</instrument>

<copy todir="${document.root}/${class.instrumented.dir}" preservelastmodified="yes">
<fileset dir="${document.root}/${class.dir}">
  <include name="**" />
  <exclude name="**/*.class" />
</fileset>
</copy>

<delete dir="${document.root}/${class.dir}" />
<mkdir dir="${document.root}/${class.dir}" />
<copy todir="${document.root}/${class.dir}" preservelastmodified="yes">
<fileset dir="${document.root}/${class.instrumented.dir}">
  <include name="**" />
</fileset>
</copy>

<delete>
<fileset dir="${ser.output.dir}">
  <include name="jcoverage.ser" />
</fileset>
</delete>
<copy file="jcoverage.ser" todir="${ser.output.dir}" />

</target>

ちとダサいんですが、Eclipseがコンパイルしたクラスがあるディレクトリ(classes)でInstrumentして(Insturumented-classesにコピーされる)、classesディレクトリを削除、んでInsturumented-classesディレクトリをclassesディレクトリにコピー、なんてことをやってます。これでWASのテスト環境がパスを通すclassesディレクトリにデバッグ埋め込み済みのコードが配置されたことになります。

あと、一点だけ異なるのがコンテナ上でもカバレッジを計測するので、ここで作成されるjcoverage.serをコンテナ上のVMが出力するディレクトリにもコピーをしなくてはいけないということです。そのディレクトリってのはWEBコンテナの起動ディレクトリっぽいですね。build.xmlの記述でいうと、コンテナ上のVMが出力するディレクトリというのが上の記述の

${ser.output.dir}

です。実体はbuild.propertiesに記述してあって、うちの環境では、

ser.output.dir=D:/IBM/Rational/SDP/6.0

となっています。ちなみにbuild.propertiesはこんな感じになっています。 build.properties

そもそもクライアントVMもコンテナのVMも同じディレクトリに出力してくれればよいのですが、なんかうまくいきませんでした。

WEBコンテナ起動

ここでWEBコンテナを起動します。ここでビルドがかかっちゃうと、またEclipseがclassesディレクトリを上書きしちゃうので、ビルドがかからないようにそおっと(??)コンテナを起動します。

EclipseでCactus起動

いつもEclipseでCactusを起動するのと変わりません。これで、クライアントで処理されるbeginXXXのメソッドの網羅率はプロジェクト内のディレクトリに出力されるし、コンテナで処理されるtestXXXのメソッドの網羅率は上に指定したディレクトリに出力されます*3

Antでレポート

WEBコンテナを落とした時点で、

  • クライアントVM上のクラスが出力したjcoverage.ser(プロジェクトのルートにある)
  • WEBコンテナのVM上のクラスが出力したjcoverage.ser(WEBコンテナの起動ディレクトリにある)

が存在することになります。最後にそれぞれのファイルをマージして一つのファイルにして、レポーティングすれば完成です。Antで以下のようにしました。

<target name="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>

<target name="merge" >
  <delete file="jcoverage_server.ser" />
  <copy file="${ser.output.dir}/jcoverage.ser" tofile="jcoverage_server.ser" />
  <merge>
    <fileset file="jcoverage*.ser">
    </fileset>
  </merge>
</target>

これを実行*4すると、プロジェクトルートのserファイルとWEBコンテナ上のserファイルがマージされ、レポートhtmlが作成されます。。


この記事は

選択肢 投票
おもしろかった 22  
そうでもない 4  
  • Tomcatでうごかねー。。カバレッジ計測まではできてるっぽいんだけど、Tomcatをshutdownしたときにコンテナ上のjcoverage.serが0byteになっちゃう。 -- きの? 2005-09-05 08:42:28 (月)
  • tomcat/binにおいたjcoverage.serはshutdownで0バイトになっちゃいますよね。解決ありました?bin以外にserを置いて、 com.jcoverage.rawcoverage.dirでVMに場所教えないといかんのかなあ。 -- みきさ? 2005-12-08 17:40:21 (木)
  • VM引数に -Dcom.jcoverage.instrumentation.interval=5 を追加すると動くよ -- jun? 2007-12-26 (水) 18:18:56

Top / Java / jcoverage / ServletなどJ2EE環境で使う。

現在のアクセス:17373


*1 Studioについてくるヤツ
*2 WebSphereなどに限らず、最近の環境はどこでもそうですよね
*3 正確にはコンテナを落としたときに出力されているかな
*4 ant merge coverage

添付ファイル: fileresult.png 1262件 [詳細] fileserversettiong.png 1163件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2021-12-14 (火) 10:53:15 (857d)