EclEmmaとWinstoneでWebアプリのカバレッジ取得

EclEmmaという神プラグインで,IDEAんときみたくWinstoneを使ってWebアプリのカバレッジが取得できたので,やり方をメモしておく。
#IDEAもEMMA使っているので,仕組み的には全く同じだった。


まずは,IDEAとEclEmmaの相違点。

  • IDEAと異なり,JDK1.4.2系でもカバレッジの取得が出来る(IDEAはJDK5以降じゃないとダメ)。
  • Eclipseのコンソールビューは,graceful exitが出来ないので(IDEAと比べ)Winstoneの停止がちょっとだけ面倒。
  • なぜか,Winstone 0.9.6じゃないとダメだった。最新の0.9.8は,終了方法が変わったのか停止してもカバレッジデータが出力されなかった(なんでや?)。ちなみに,IDEAの場合,0.9.6/0.9.8共に成功。

目立った違いはこれくらいで,とかくEclEmmaの完成度は高い。IDEAのそれと,まったくもって遜色がないし,JDK1.4.2で動く点でIDEAより優れている。
あえて難点を挙げると言えば,Webアプリのプロジェクトの標準構成を持っていないので,それなりに工夫がいるくらい。
#だけど,Eclipseに対してこうゆうケチを付けるのはフェアじゃないよなぁ。


前置きはこれくらいにして,やってみたことを以下に記す。なお,Eclipseは3.2。すっかりプラグイン事情には疎くなったので,WTPとかTomcatプラグインとかは使ってない。

プロジェクトの作成

普通にJavaプロジェクトを作成する。ソースパスとかはご自由に。
プロジェクトの目的はWebアプリなので,「./web」フォルダを用意しておく。このフォルダをWinstoneに直接認識させるため,libフォルダとかもあらかじめ準備しとく。でもって,ソースパスの出力先に「./web/WEB-INF/classes」を指定する。
一応,JUnitも動かしてみたかったんで,ソースパスはプロダクトコード用とテストコード用とにわけといた。

#プロジェクトの構造:winstone.jarとかjunit.jarはユーザライブラリに登録しててもイイ。
#あと,winstone.jarにservlet-apiも含まれているので,servlet-api.jarは無くても平気。



#ビルドパスの設定:せっかくだからテストコードの出力先は,プロダクトコードと別にしてある。


プロジェクトホーム直下のlibフォルダは,Winstoneが利用するライブラリ置き場で,JasperとかJDBCドライバとか入れておく。今回は,JSPも利用するのでJasperを入れてある(断っておくけど,JSPカバレッジ取れないよ)。
libフォルダの中身はこんな感じ。

ant.jar, commons-el.jar, commons-logging.jar, jasper-compiler.jar, jasper-runtime.jar, jsp-api.jar, log4j-1.2.9.jar

winstone.propertiesはあとで説明する。

コーディング

まあテキトウに。とりあえず,こんなやっつけサーブレットを書いたとしよう。

package test;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SampleServlet extends HttpServlet {

  public void init(ServletConfig config) throws ServletException {
    System.out.println("init");
  }

  protected void doGet(
      HttpServletRequest req,
      HttpServletResponse res
  ) throws ServletException, IOException {
    PrintWriter writer = res.getWriter();
    writer.println("<html>");
    writer.println("<body>");
    writer.println("Hello World.");
    writer.println("</body>");
    writer.println("</html>");
  }
}

web.xmlもお忘れ無く。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                             http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <servlet>
    <servlet-name>SampleServlet</servlet-name>
    <servlet-class>test.SampleServlet</servlet-class>
    <load-on-startup>0</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>SampleServlet</servlet-name>
    <url-pattern>/Sample</url-pattern>
  </servlet-mapping>
</web-app>

せっかくだから,JSPも書いとくか。

===index.jsp===
<%@page contentType="text/html; charset=UTF-8" %>
こんにちは,世界。<br>
<a href="./Sample">Sample Servlet</a>

Winstoneの起動準備

だいたい,こんな感じの実行構成を作成する。


JUnitの実行はEclEmmaがよろしくやってくれるので,ここでは割愛。目玉−−と言うほど大げさなもんじゃないが,Winstoneの起動がポイント。こいつの実行構成を以下に示す。

といっても,メイン・クラスを「winstone.Launcher」に指定して,カバレッジの測定対象のみを指示するだけでいい。あと引数を指定するのは,面倒なのでwinstone.propertiesで代用する。

webroot=./web
prefix=/coverageTest
controlPort=8081
useJasper=true
javaHome=c:/java/jdk142_10

最後の「javaHome」はJasperに渡すJDKの場所。これは開発者の環境依存なんで,本来なら引数で個別指定するのが望ましいんだろうな。
winstone.propertiesには,データソースとかも書けるから,詳しくはWinstoneのマニュアル見てくれ。


実行構成に必要なのはもうひとつ,Winstoneの停止。coberturaもそうだったけど,この手のツールはJVM終了時に測定情報を吐き出すので,JVMはgracefulに終了してくんないといけない。残念なことに,Eclipseのコンソールビューにある「終了」ボタンはJVMを強制終了させちゃうので,もれなく測定情報もロストしてしまう。
そんなこんなあって,正式な手順でWinstoneを停止させないとイケナイとなるわけだ。


Winstoneの停止に関する実行構成は,こんな感じ。


メイン・クラスを「winstone.tools.WinstoneControl」とし,引数に「shutdown」を指定するだけでよい。ついで言えば,この実行構成は別にEclipseから実行する必要はまったくない。バッチ組んでおいてもいいし,外部ツールに登録しておいてもいい。

Winstoneの実行とカバレッジの取得

準備ができたんで,Winstoneを起動してみる。起動は至って簡単。カバレッジ測定付き起動で,先ほど登録した「winstoneの起動」を実行する。
#EclEmmaのスゴイところは,こんな具合に何ら特別な事をせず使えることだ。


Winstoneだから,わりあいサクっと起動するんで,あとは通常のWebアプリ同様にWebブラウザから操作すればよい。
ちなみに,さっきの設定だとエントリポイントは,以下のURLになる。

http://localhost:8080/coverageTest/

注意すべき点ってほどでもないけど,知らないとビックリすると思うので,一応書いとくが,一度でもイイから測定対象のプログラムを動かさないとWinstone停止時にEclEmmaにお叱りを受ける(測定データがないから)。とは言え,動かさなければ測定データがないのは当たり前なので,軽くスルーしたところで痛くもかゆくもないんだけどね。
#今回,提示したサンプルは,web.xmlにload-on-startupを設定しといたから,
Winstone起動すれば一度は動くんで,文句言われることはない。


ひとしきり動かしたなら,Winstoneを停止する。何度も言うが,コンソールビューの「終了」ボタンを押してはダメだ。これもさっき用意した「winstoneの停止」を実行して,gracefulに終了させる。


運悪く(?)測定データが取得できないと,こんなダイアログが表示される。


あたしが試した限りでは,

  • 対象プログラムを一度も動かしてない。
  • コンソールビューの「終了」ボタンを押して停止した。
  • Winstone 0.9.8を使った(なぜに?)。

のいずれかで見た。


運良く(?)計測が成功すると,ご覧のようにカバレッジ情報が表示され,めでたし,めでたしとなる。

#不要な測定データの削除は,この画面でDELキーを押すとできるそうだ。



#エディタでもカバレッジが一目瞭然。


文書にすると結構あるけど,大したことやってないんだよね。そう思えば,この程度の手間でWebアプリのカバレッジも測定できるってのは,実に便利な世の中になったもんだなぁ。

NetBeansでEclEmmaやIDEAのカバレッジ測定みたいなのは本質的にムリだと思ってる

NetBeansにもEMMAベースのカバレッジ測定ツールはあるよ。

ただ,それでもEclEmmaやIDEAみたく,Winstoneをちゃっかり利用して「Javaアプリなんだけど,Webアプリでーす」みたいなコスいマネは出来ないハズだ。


なぜかって?


それは,EclipseやIDEAと違い,NetBeansには実行構成って考え方がないからだ。あらためて思えば不思議な話なんだけど,NetBeansって,

  • Tomcatの)Webアプリケーションプロジェクトなら,Tomcatでしか実行できない
    • GlassfishJBossに切り替えるには,いちいちプロジェクトプロパティを開かないとダメ。
  • Webアプリケーションプロジェクトなんだけど,ちょっとJavaアプリを実行とかもできない。
    • ちょっとウソ。一応,「Run File」ってメニューはある。ただ,引数とか指定できないっぽい。

...という面倒臭さがある。とはいえ,究極的にはビルドスクリプトを自分で好きにカスタマイズできるんで,やる気になりゃ何でも出来るんだろうけど,EclipseやIDEAに比べるとハードルは高い。


まあ,NetBeansはそうゆう割り切りをすることで,実行構成の設定を気にしなくても良いようにしたんだろう。それはそれで,致し方あるまいよ。