ちょっと話題の記事

Jenkinsを使ってビルド~単体テストまで

2013.02.18

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

弊社ブログでも何度か取り上げられているJenkinsですが、今回はこのCIツールを使って「ビルド~単体テスト」までを行いたいと思います。
具体的に何をやるかといえば、「ソースのビルド」「チェックスタイルの実行」「FindBugsの実行」「Junitの実行」といったことを実施します。

Antのインストール

実行環境にAntをインストールする必要があります。

以下のコマンドでAntをダウンロードして解凍し任意の場所に置きます。今回は/usr/local/antに置くこととします。

wget http://ftp.yz.yamagata-u.ac.jp/pub/network/apache//ant/binaries/apache-ant-1.8.4-bin.tar.gz
tar zxvf apache-ant-1.8.4-bin.tar.gz
mv apache-ant-1.8.4 /usr/local/ant

プロジェクトを作成する

今回使用するプロジェクト構成は以下のようにします。

プロジェクト構成2
src/main/javaパッケージ配下にアプリのソースコードがあり、src/test/javaパッケージ配下には単体テスト用のソースコードがあります。今回はfindBugsやチェックスタイルも同プロジェクト直下に配置してあります。
今回使用するbuild.xmlは以下のようにします。

<?xml version="1.0" encoding="UTF-8"?>
<project name="JenkinsSample" default="unit-test" basedir=".">
    <property name="webapp" value="${basedir}/src/main/webapp"/>
    <property name="compile.src" location="${basedir}/src/main/java"/>
    <property name="compile.resources" location="${basedir}/src/main/resources"/>
    <property name="compile.dest" location="${webapp}/WEB-INF/classes"/>
    <property name="compile.test.src" location="${basedir}/src/test/java"/>
    <property name="compile.test.resources" location="${basedir}/src/test/resources"/>
    <property name="compile.test.dest" location="${basedir}/target/test-classes"/>
    <property name="tomcat.dir" value="/usr/local/tomcat/lib"/>
    <property name="findbugs.dir" value="${basedir}/findbugs"/>
    <property name="report.dir" value="${basedir}/report"/>
    <property name="report.test.dir" value="${basedir}/report/test"/>
    <!-- =================================
          target: init
         ================================= -->
    <target name="init" description="initialize">
        <mkdir dir="${report.test.dir}"/>
        <delete file="${report.dir}/**/*.xml"/>
    </target>
    <!-- =================================
          target: compile
         ================================= -->
    <target name="compile" depends="clean">
        <mkdir dir="${compile.dest}"/>
        <javac srcdir="${compile.src}" destdir="${compile.dest}" encoding="UTF-8"
            includeantruntime="false">
            <classpath>
                <fileset dir="${webapp}/WEB-INF/lib">
                    <include name="*.jar"/>
                </fileset>
                <pathelement location="${tomcat.dir}/servlet-api.jar" />
                <pathelement location="${tomcat.dir}/annotations-api.jar" />
                <pathelement location="${tomcat.dir}/el-api.jar" />
                <pathelement location="${tomcat.dir}/jasper.jar" />
                <pathelement location="${tomcat.dir}/jsp-api.jar" />
            </classpath>
        </javac>
        <copy todir="${compile.dest}">
            <fileset dir="${compile.resources}"/>
        </copy>
    </target>
    <target name="test-compile">
        <mkdir dir="${compile.test.dest}"/>
        <javac srcdir="${compile.test.src}" destdir="${compile.test.dest}" encoding="UTF-8"
            includeantruntime="false">
            <classpath>
                <fileset dir="${webapp}/WEB-INF/lib">
                    <include name="*.jar"/>
                </fileset>
                <fileset dir="${basedir}/lib">
                    <include name="*.jar"/>
                </fileset>
                <pathelement location="${tomcat.dir}/servlet-api.jar" />
                <pathelement location="${tomcat.dir}/annotations-api.jar" />
                <pathelement location="${tomcat.dir}/el-api.jar" />
                <pathelement location="${tomcat.dir}/jasper.jar" />
                <pathelement location="${tomcat.dir}/jsp-api.jar" />
            </classpath>
        </javac>
        <copy todir="${compile.dest}">
            <fileset dir="${compile.resources}"/>
        </copy>
    </target>
    <!-- =================================
          target: checkstyle
    ================================= -->
    <target name="checkstyle" >
        <taskdef resource="checkstyletask.properties"
                   classpath="${basedir}/checkstyle-5.5-all.jar" />
         <checkstyle config="${basedir}/checkstyle.xml">
            <fileset dir="${basedir}"
                includes="**/*.java"
                excludes="test/**"/>
             <formatter type="xml" tofile="${report.dir}/checkstyle_report.xml"/>
        </checkstyle>
    </target>
    <!-- =================================
          target: findbugs
    ================================= -->
    <target name="findbugs">
        <mkdir dir="${report.dir}"/>
        <taskdef name="findbugs"
            classname="edu.umd.cs.findbugs.anttask.FindBugsTask"
            classpath="${findbugs.dir}/lib/findbugs-ant.jar">
        </taskdef>
        <findbugs home="${findbugs.dir}"
                  output="xml"
                  outputFile="${report.dir}/findbugs_report.xml" >
            <class location="${compile.dest}" />
        </findbugs>
      </target>
    <!-- =================================
          target: junit
    ================================= -->
    <target name="unit-test" depends="init,compile,test-compile,checkstyle,findbugs" description="execute Junit">
        <delete>
            <fileset dir="${report.test.dir}" includes="TEST-*"/>
        </delete>
        <junit fork="yes" haltonfailure="false"  >
        <formatter type="xml" usefile="true" />
            <classpath>
                <fileset dir="${basedir}/lib">
                   <include name="*.jar"/>
                </fileset>
                <fileset dir="${webapp}/WEB-INF/lib">
                   <include name="*.jar"/>
                </fileset>
                <pathelement location="${compile.dest}"/>
                <pathelement location="${compile.test.dest}"/>
            </classpath>
            <batchtest fork="yes" todir="${report.test.dir}" >
                <fileset dir="${compile.test.src}" >
                    <include name="**/*Test.java"/>
                </fileset>
            </batchtest>
        </junit>
    </target>
    <!-- =================================
            target: clean
        ================================= -->
    <target name="clean" description="clean up">
        <delete dir="${compile.dest}"/>
        <delete dir="${compile.test.dest}"/>
    </target>
</project>

少し長いですが、アプリソースのコンパイル、テストソースのコンパイル、チェックスタイルの設定、findBugsの設定、JUnitの設定を記述してあります。

Jenikinsの設定

Antの設定

Jenkinsのトップから「Jenkinsの管理」>「システムの設定」を選択します。
「Ant追加」ボタンをクリックし「自動インストール」のチェックを外します。
「名前」に「ant」と入力し、「ANT_HOME」に「/usr/local/ant」と入力し、「保存」ボタンをクリックします。

プラグインの設定

jenkinsの初期状態ではチェックスタイル、FindBugsは使用できないのでプラグインをインストールします。
Jenkinsのトップから「Jenkinsの管理」>「プラグインの管理」を選択します。次に「利用可能」タブを選択し、「Checkstyle Plugin」「FindBugs Plugin」にチェックを入れ、「再起動せずにインストール」ボタンをクリックします。
プラグイン

問題なければ「成功」と表示されます。
インストール完了

ジョブの作成

トップ画面に戻り、新規ジョブ作成をします。
ジョブ名を入力し、「フリースタイル・プロジェクトのビルド」を選択し、「新規ジョブ作成」をクリックします。
新規ジョブ作成
次に本来はSVNの設定をしますが、SVMの設定に関しては既に弊社ブログ( CIツール Jenkins を使ってみた)で取り上げていますので、今回は省略したいと思います。この先はSVNは設定済みとして進めます。

プロジェクトの設定

Antの設定

「ビルドの手順追加」から「Antの呼び出し」を選択します。「使用するAnt」に「ant」を選択し、「ターゲット」に「unit-test」と入力し、build.xmlに記述しているtargetを設定します。
「高度な設定」をクリックし、「ビルドファイル」に「JenkinsSample/build.xml」と入力します。

チェックスタイルの設定

「ビルド後の処理の追加」から「Checkstyle警告の集計」を選択し、「集計するファイル」に「JenkinsSample/report/checkstyle_report.xml」と入力し、Antから実行されたCheckstyleの実行結果ファイルを指定しています。

FindBugsの設定

「ビルド後の処理の追加」から「FindBugs警告の集計」を選択し、「集計するファイル」に「JenkinsSample/report/findbugs_report.xml」と入力します。

JUnitの設定

「ビルド後の処理の追加」から「JUnitテスト結果の集計」を選択し「テスト結果XML」に「JenkinsSample/report/test/**/TEST-*.xml」と入力します。JUnitのテスト結果はテストクラスごとに出力されるため正規表現で指定します。
出力されるファイル名は「TEST-パッケージ名.クラス名.xml」になります。

これで設定は終わりなので「保存」ボタンをクリックします。

実行してみよう

「ビルド実行」をクリックします。
「ビルドの履歴」に実行日付けのリンクが作成されるのでクリックします。すると以下のように結果が表示されます。
ビルド結果
チェックスタイル、FindBugs、Junitの結果が表示されているが分かります。またそれぞれの結果をクリックすると以下のように結果の詳細が分かります。
チェックスタイルの結果
FindBugsの結果
JUnitの結果
さらに失敗したテストケースをクリックすると詳細が表示されます。
JUnt結果詳細
今回の例では結果の値が3になるはずが、2だったということが分かります。

まとめ

今回、実施した「チェックスタイル」「Findbugs」「JUnit」はプロジェクトで良く使われているものかと思います。Jenkinsを使って定期的に実行することで、視覚的に実行結果の推移も分かり、プロジェクトを進めていく上で役立つのではないでしょうか。みなさんも良かったら実施してみてください。