#topicpath ---- #contents [[クライアントサイドのjcoverage>Java/jcoverage]]に関しては何とか動いたようです。いよいよサーバサイドのカバレッジ計測をやってみようと思います。確認は以下のような環境で行いました。 |BGCOLOR(#CCFFFF):LEFT:プロダクト|BGCOLOR(#CCFFFF):LEFT:バージョン|BGCOLOR(#CCFFFF):LEFT:役割| |LEFT:WebSphere|LEFT:WebSphere 5.0.2テスト環境((Studioについてくるヤツ))|LEFT:WEBコンテナ| |LEFT:Cactus|LEFT:1.7.1|LEFT:サーバサイドテスティングフレームワーク| |LEFT:Junit|LEFT:3.8.1|LEFT:テスティングフレームワーク| |LEFT:jcoverage|LEFT:1.0.5|LEFT:カバレッジツール| [[Cactus>Java/Cactus]]とはサーバサイドのテスティングフレームワークです。JUnitのクラスを拡張して、WEBコンテナ上でテストを行うためのクラス群を提供します。 具体的には、requestパラメータにいろいろな値をセットしてブラウザのリクエストをシミュレーションすることや、ブラウザへ返却される画面に正しく値がセットされてるかをチェックするクラスなどを提供してくれます。 さて、[[前回>Java/jcoverage]]にJUnitとの連携まではやりましたが、今回がいままでと違うところは''WEBコンテナ上で稼働する箇所とクライアントで稼働する箇所がある''というところです。つまりリクエスト情報を構築してリクエストを放るまではクライアント側のJavaVM,リクエストを受けて処理をしてクライアントに返すまではWEBコンテナ上のJavaVM、という方式になります。クライアント側のカバレッジ計測についてはある意味いままでと変わらないのですが、WEBコンテナで稼働する部分のカバレッジ計測をどうするかというところがポイントになります。いろいろ調べた結果、以下のようなやり方でやればよい(ような気がする)事がわかりました。 -クライアント側はクライアント側で、コンテナ側はコンテナ側でそれぞれ計測して、マージする -計測するにはデバッグ埋め込み済みのコードをデプロイする必要がある -(特にWASだけかも?)WEBコンテナにjcoverageのjarをパスを通して認識させておく 難しいのは、デプロイするearにアーカイブされるクラスにどのようにデバッグを埋め込むか、ですね。通常開発環境でのコーディング・テストフェーズでは、自分でアーカイブを作ることはせず、開発環境が勝手にデプロイしてくれることが多いからです((WebSphereなどに限らず、最近の環境はどこでもそうですよね))。これに関してはclassesにデバッグ埋め込み済みのコードを配置するようビルドする、ことで解決できそうです。 さて例でやってみます。 **準備 [#g4459cec] WebSphereのテスト環境でjcoverageを使うときにサーバ側でエラーが発生してしまうようで、 WebSphereテスト環境 >> 環境 >> WebSphere特定クラスパス でjcoverage.jarを追加する必要があるみたいです。Tomcatなどでやるときもcommon/libとかに入れておく必要があるのかな? **手順 [#oa26c415] 手順は、 - Eclipseでコンパイル - AntでInstrument - WEBコンテナ起動 - EclipseでCactus起動 - Antでレポート となります。ポイントは''デフォルトではclassesがクラスパスに設定されてしまうので、instrumentしたファイルがclassesに配置されるようビルドする''って事です。あと、Eclipseは自動的にビルドする機能がありますが、そうするとせっかくInstrumentしたファイルを上書きしてしまうので、自動ビルドをOFFにしておきました。 *** プロジェクト作成 [#y4bf2953] プロジェクト名はJCoverageTestWebとしました。CVSは[[こちら:http://www.masatom.in/cgi-bin/viewcvs.cgi/JCoverageTestWeb/]] *** Eclipseでコンパイル [#rb770184] 今回は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 [#se61130a] 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:http://www.masatom.in/cgi-bin/viewcvs.cgi/JCoverageTestWeb/build.properties]] そもそもクライアントVMもコンテナのVMも同じディレクトリに出力してくれればよいのですが、なんかうまくいきませんでした。 ***WEBコンテナ起動 [#w844263f] ここでWEBコンテナを起動します。ここでビルドがかかっちゃうと、またEclipseがclassesディレクトリを上書きしちゃうので、ビルドがかからないようにそおっと(??)コンテナを起動します。 ***EclipseでCactus起動 [#bedad78b] いつもEclipseでCactusを起動するのと変わりません。これで、クライアントで処理されるbeginXXXのメソッドの網羅率はプロジェクト内のディレクトリに出力されるし、コンテナで処理されるtestXXXのメソッドの網羅率は上に指定したディレクトリに出力されます((正確にはコンテナを落としたときに出力されているかな))。 ***Antでレポート [#w6b33aeb] WEBコンテナを落とした時点で、 -クライアントVM上のクラスが出力したjcoverage.ser(プロジェクトのルートにある) -WEBコンテナのVM上のクラスが出力したjcoverage.ser(WEBコンテナの起動ディレクトリにある) が存在することになります。最後にそれぞれのファイルをマージして一つのファイルにして、レポーティングすれば完成です。Antで以下のようにしました。 ---- この記事は #vote(おもしろかった,そうでもない) #comment #topicpath SIZE(10){現在のアクセス:&counter;}