スポンサーリンク

jUnit3 をコンソールで実行するための導入手順 (Eclipseを使わずに,Ant+jUnitDocletで頑張る)

Eclipseを使わずに,コマンドラインからjUnitを利用する方法。

重いIDE無しに Javaテスト駆動開発するための入門。


解説内容は

  • (1)jUnitを入手
  • (2)試用してみる
  • (3)一つのクラスに対して単体テストを実行
  • (4)複数のクラスに対して単体テストを実行
  • (5)Antを使う(テストケースを単独に指定)
  • (6)Antを使う(フォルダ階層中のテストケースを全部実行)
  • (7)テストケースを自動生成する

の7項目。

(1)jUnitを入手

単体テストツールjUnitは,バージョン3,4で構成・使い方がだいぶ変わった。

違いは,

  • アノテーション対応
  • クラス名にTestを含まなくてよい

など。

JUnit 4 & TestNG
http://www.okisoft.co.jp/esc/testing/...

今はまだjUnit4の情報・利用実績は3に比べそれほど多くない。

以下ではjUnit3を使う事にする。



下記URLの画面上部,Download Junit から,3.8.1 > junit3.8.1.zip をダウンロード。

http://www.junit.org/

解凍するとjunit.jarがある。


(2)試用してみる

利用のために必要なのは,-cp オプションを使って前項のjarをクラスパスに含めること。


jarが動くかどうか試してみる。

junit.jarの存在するディレクトリ上で,コマンドプロンプトから

	java -cp junit.jar;. junit.swingui.TestRunner junit.samples.AllTests

とする。

GUIが現れて黄緑色のバーがぐんぐん伸びて,テスト成功になればOK。


なお,jUnit4 ではフォルダ構成が変わっているため,このテストは実行できない。

(3)一つのクラスに対して単体テストを実行

一つだけのクラスに対して,単体テストを行ないながら開発を進めてみよう。

テスト対象のクラスは Hello という文字列を出力する事にする。


まずは,テスト対象のクラスを作る前に,テストケースを作る。


HelloTest.java

import junit.framework.TestCase;

public class HelloTest extends TestCase {
	public void testTalk() {
		Hello hello = new Hello();
		String s = hello.talk();
		assertEquals( "Hello", s );
	}
}

このテストケースを作成することによって,クラスHelloを作る前から使い方がわかる


作る前から使いましょう。


Andy Hunt著,「アジャイルプラクティス」5章,アジャイルなフィードバック


なお,テストケースの書き方:

テスト用メソッド一覧
http://www.javaroad.jp/opensource/js_junit2.htm


この時点で,テストケースをコンパイル。

同じディレクトリにjunit.jarを置いておく。

	javac -cp junit.jar;. HelloTest.java

クラスHelloをまだ作ってないので,このコンパイルは失敗する。

したがって,「次はコンパイルが通るように Hello.java を作ろう」という目標が発生する。



そこで同ディレクトリに Hello.java を作成:

public class Hello
{
	public String talk()
	{
		return "Hoge";
	}
}

再度コンパイル

	javac -cp junit.jar;. *.java


コンソールでjunitテストを実行。実行したいテストケースを指定する

	java junit.textui.TestRunner HelloTest

HelloではなくHogeと返したから,このテストは失敗する。

.F
Time: 0.016
There was 1 failure:
1) testTalk(HelloTest)junit.framework.ComparisonFailure: expected:<...ello> but
was:<...oge>
        at HelloTest.testTalk(HelloTest.java:7)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

FAILURES!!!
Tests run: 1,  Failures: 1,  Errors: 0

...ello,...ogeのように,返り値と期待値との差分を検出してくれる。


Hello.javaを修正:

public class Hello
{
	public String talk()
	{
		return "Hello";
	}
}

再度コンパイルし,テストを実行すると

.
Time: 0

OK (1 test)

OKが出る。



CUIではなく,緑や赤のバーをGUIで見たいならば,junit.textui.TestRunnerのかわりに

	java -cp junit.jar;. junit.swingui.TestRunner HelloTest

とする。

(4)複数のクラスに対して単体テストを実行

複数のテストケースがある場合,それらをまとめて呼び出すクラスを作る。


AllTests.java

import junit.framework.Test;
import junit.framework.TestSuite;

public class AllTests {

	public static void main( String[] args ) {
		junit.textui.TestRunner.run( AllTests.class );
	}

	public static Test suite() {
		TestSuite suite = new TestSuite( "default test" );

		// ここにテストケースを追加
		suite.addTest( new TestSuite( HelloTest.class ) );
		suite.addTest( new TestSuite( HogeTest.class ) );

		return suite;
	}
}


実行時は

	java -cp junit.jar;. junit.textui.TestRunner AllTests

これで全テストが走る。



以上はantを使わず,コンソールだけでjUnitを利用するサンプル。

下記サイトが参考になる。

JUnit 編 テストの真髄を掴む
http://www.javainthebox.net/publicati...

(5)Antを使う(テストケースを単独に指定)

jUnitの実行をAntタスクにすれば,AllTestsみたいなまとめクラスが不要になる。


※Antの基礎は下記記事を参照。

繰り返し実行可能なコンパイルバッチ
http://language-and-engineering.hatenablog.jp/entry/20081208/1228708657

junit + antの組み合わせは下記サイトなどを参考に。

JUnit の基礎の基礎 (1) + ant での実行
http://www63.tok2.com/home2/jd4/JUnit...

Ant徹底活用第4回:システム開発によく使うタスク(2)
http://www.stackasterisk.jp/tech/java...

jUnit Task
http://www.jajakarta.org/ant/ant-1.6....


実行のためには,まずjunit.jar を Antのインストールディレクトリの \lib にコピー。


テストケース HelloTest.java と同じフォルダに build.xml を作り,jUnitタスクのtestエレメントを含ませる。

<project name="junittemp" default="runtests">

	<property name="builddir" value="." />

	<target name="runtests">
		<junit haltonfailure="false">
			<formatter type="plain" usefile="false" />
			<classpath>
				<pathelement location="${builddir}"/>
			</classpath>
			<test name="HelloTest"/>
		</junit>
	</target>

</project>

test name=の部分に単独でテストケース名をそれぞれ指定している。


これでコンソールから

	ant runtests

でテストが実行され,コンソールに詳細結果が出力される。

(6)Antを使う(フォルダ階層中のテストケースを全部実行)

フォルダを再帰的にたどって処理するのは,Antが得意とするところ。

この場合,jUnitタスクのbatchtestエレメントを使う。


build.xmlの例:

<project name="junittest" default="junit_exec">
	<property name="build_dir"       value=".."/>
	<property name="test_case_dir"   value="${build_dir}/src/test"/>
	<property name="classes"         value="${build_dir}/classes/main"/>
	<property name="test_classes"    value="${build_dir}/classes/test"/>
	<property name="testsuite"       value="${build_dir}/classes/test"/>
	<property environment="env"/>

	<path id="classpath_default">
		<pathelement path="${classes}" />
		<pathelement path="${test_classes}" />
		<pathelement path="${env.JAVA_HOME}/lib/tools.jar" />
		<fileset dir="${env.ANT_HOME}/lib">
			<include name="**/*.jar"/>
		</fileset>
	</path>

	<target name="junit_compile">
		<javac 
			fork="true" 
			srcdir="${test_case_dir}" 
			destdir="${test_classes}"/>
	</target>

	<target name="junit_exec" depends="junit_compile">
		<junit fork="yes" haltonfailure="no">
			<formatter type="plain" usefile="no"/>
			<classpath refid="classpath_default" />
			<batchtest fork="yes">
				<fileset dir="${test_case_dir}">
					<include name="**/*Test*.java"/>
				</fileset>
			</batchtest>
		</junit>
	</target>

</project>

それぞれテストケースをコンパイルするタスクと,テストケースを実行するタスク。

property environment=でシステム環境変数を参照できる。


なお,下記のようなディレクトリ構成を仮定した。

build
   bin
     ant用のxml

   src
     main (ソース)
       java
          jp
             co
                ..(以下パッケージ構成が続く)

     test (テストケース格納用)

   classes
     main
     test

これで

	ant -file build.xml junit_exec

と打てば

Buildfile: build.xml

junit_compile:
    [javac] Compiling 1 source file to D:\〜〜\build\classes\test

junit_exec:
    [junit] Testsuite: TestHello
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] ------------- Standard Output ---------------
    [junit] Hoge
    [junit] ------------- ---------------- ---------------
    [junit]
    [junit] Testcase: testHoge took 0 sec

BUILD SUCCESSFUL
Total time: 2 seconds

こんな風にコンパイル+テストが自動実行される。

(7)テストケースを自動生成する

たくさん既存のクラスがある場合は,テストケースをいちいち作るのは面倒だ。

この場合,既存のクラスからjUnitのテストケースの雛型を自動生成できる。*1


本当はEclipseを使うのが一番簡単なのだが,ここではコンソールのみで JunitDocletを使って行なう。

junitDoclet
http://www.junitdoclet.org/download/index.html
http://www.geocities.co.jp/Playtown/1245/@geoboard/8.html

ドックレットとは
http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/javadoc/doclet/overview.html

最新版をダウンロードしたら,\JUnitDoclet.1.0.2\doc\ant_target\readme.txt に解説があるので見る。

\JUnitDoclet.1.0.2\JUnitDoclet.jar を, Antのインストールディレクトリの\lib にコピー。


これでAntでJavadocタスクを書けばよい。その際の注意点:

build.xmlの例
http://hpcgi2.nifty.com/owa4/wiki/wiki.cgi?p=JUnitDoclet
テストクラスをコンパイルする際には元クラスが必要なのでクラスパスに含める

不適切なコンストラクタ呼び出しをしてしまうなど,完璧ではない。コンパイルエラーがあったら手動で訂正する。
http://www.junitdoclet.org/faq/index.html#id000184


build.xmlの例 (もし日本語を使う場合はUTF8で保存すること)

<project name="junitdoclet_test" default="junitdoclet">

	<property name="package"         value="jp.co.〜パッケージ名〜"/>
	<property name="package_exclude" value="${package}.persis.entity"/>
	<property name="build_dir"       value=".."/>
	<property name="source"          value="${build_dir}/src/main"/>
	<property name="test_case_dir"   value="${build_dir}/src/test"/>
	<property name="classes"         value="${build_dir}/classes/main"/>
	<property name="test_classes"    value="${build_dir}/classes/test"/>
	<property name="testsuite"       value="${build_dir}/classes/test"/>
	<property environment="env"/>

	<!-- デフォルトクラスパス -->
	<path id="classpath_default">
		<pathelement path="${classes}" />
		<pathelement path="${test_classes}" />
		<pathelement path="${env.JAVA_HOME}/lib/tools.jar" />
		<fileset dir="${env.ANT_HOME}/lib">
			<include name="**/*.jar"/>
		</fileset>
	</path>

	<!-- テストケース全削除 -->
	<target name="test_clean">
		<delete dir="${test_case_dir}" />
		<mkdir  dir="${test_case_dir}" />
		<delete dir="${test_classes}" />
		<mkdir  dir="${test_classes}" />
	</target>

	<!-- テストケースの雛型を生成 -->
	<target name="junitdoclet">
		<javadoc
			packagenames    = "${package}.*"
			excludepackagenames    = "${package_exclude}"
			sourcepath      = "${source}/java"
			defaultexcludes = "yes"
			doclet          = "com.objectfab.tools.junitdoclet.JUnitDoclet"
			docletpathref   = "classpath_default"
			additionalparam = "-d ${test_case_dir} -buildall">
		</javadoc>
	</target>

	<!-- テストケースをコンパイル -->
	<target name="junitcompile" depends="junitdoclet">
		<javac srcdir="${test_case_dir}" destdir="${test_classes}" debug="on">
			<classpath refid="classpath_default" />
		</javac>
	</target>

	<!-- 全テスト実行 -->
	<target name="junittest" depends="junitcompile">
		<junit fork="yes" haltonfailure="no">
			<formatter type="plain" usefile="no"/>
			<classpath refid="classpath_default" />
			<batchtest fork="yes">
				<fileset dir="${test_case_dir}">
					<include name="**/*Test*.java"/>
				</fileset>
			</batchtest>
		</junit>
	</target>

</project>  

テストケース自動生成の際に,エンティティクラスのテストケースのsetter/getterのコンパイルでエラーになる事がある。

そこで,ここではそれらのクラスをexcludepackagenamesを使って除外してある。

コンソールから

	ant test_clean
	ant junittest

これで,テストケースの雛型が自動生成される。


 

*1:TDDの原則には反する。