AntでdjUnitタスクを実行する方法

今更ながらAntでdjUnitタスクを実行する方法です。
Eclipseが新しくなりdjUnitを使用できなくなってしまったが、プロジェクトではdjUnitのテストを使い続けたい場合に役に立つと思います。

##動作環境
Ant 1.9.7
jp.co.dgic.eclipse.jdt.djunit_3.5.x_0.8.6.zip
jUnit4
Eclipse Release 4.7.0 (Oxygen)

##プロジェクトの構造
テスト対象クラス、テストクラスを各2つ作成し、Ant、djUnit、jUnitから必要なjarをtest/libフォルダにコピーします。

| コピー元 | jar | 備考 |
|:--|:--|:--|
| Ant | ant-junit4-1.9.7.jar |※使用するantのバージョンと合わせる必要がある|
| djUnit | asm-3.1.jar | asm-1.5.3.jar、asm-2.2.1.jarは不要 |
| | asm-attrs-1.5.3.jar ||
| | djunit.jar ||
| | jakarta-oro-2.0.7.jar ||
| | jcoverage-djunit-1.0.5.jar ||
| jUnit | junit.jar ||
| | hamcrest-core-1.3.jar||
![Screenshot from 2019-08-25 18-43-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132879/47a32083-3cbe-760d-485e-0c9d1e4a9fc2.png)

###テスト対象クラス
```java:HelloService.java
package com.example;

public class HelloService {

	private String name;
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return this.name;
	}
	
	public String getMessage() {
		return String.format("Hello %s!", this.getName());
	}
	
	public void sayHello() {
		System.out.println(this.getMessage());
	}
}
```
```java:CalculateService.java
package com.example;

public class CalculateService {

	public enum Operation {
		ADD,
		SUBTRACT,
		MULTIPLY,
		DIVIDE
	};

	private int v1;
	private int v2;
	private Operation op;
	
	public void setValue1(int value) {
		this.v1 = value;
	}
	
	public void setValue2(int value) {
		this.v2 = value;
	}
	
	public void setOperation(Operation op) {
		this.op = op;
	}
	
	public float getResult() {
		switch (this.op) {
		case ADD:
			return this.v1 + this.v2;
		case SUBTRACT:
			return this.v1 - this.v2;
		case MULTIPLY:
			return this.v1 * this.v2;
		case DIVIDE:
			if (this.v2 == 0) throw new IllegalArgumentException("value2 must not be zero.");
			return (float)this.v1 / this.v2;
		}
		throw new IllegalArgumentException("operation isn't specified.");
	}
	
	public void calculate() {
		String opString = "?";
		switch (this.op) {
		case ADD:
			opString = "+";
			break;
		case SUBTRACT:
			opString = "-";
			break;
		case MULTIPLY:
			opString = "*";
			break;
		case DIVIDE:
			opString = "/";
			break;
		}
		System.out.println(String.format("%d %s %d = %.3f", this.v1, opString, this.v2, this.getResult()));
	}
}
```
###テストクラス
```java:HelloServiceTest.java
package com.example;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Before;
import org.junit.Test;

import jp.co.dgic.testing.common.virtualmock.MockObjectManager;

public class HelloServiceTest {

	@Before
	public void init() {
		MockObjectManager.initialize();
	}
	
	@Test
	public void test001() {
		HelloService service = new HelloService();
		service.setName("Japan");
		assertThat(service.getMessage(), is("Hello Japan!"));
		
		MockObjectManager.setReturnValueAtAllTimes(HelloService.class, "getName", "World");
		assertThat(service.getMessage(), is("Hello World!"));
		
		service.sayHello();
		MockObjectManager.assertCalled(HelloService.class, "sayHello");
	}
}
```
```java:CalculateServiceTest.java
package com.example;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Before;
import org.junit.Test;

import com.example.CalculateService.Operation;

import jp.co.dgic.testing.common.virtualmock.MockObjectManager;

public class CalculateServiceTest {

	@Before
	public void init() {
		MockObjectManager.initialize();
	}
	
	@Test
	public void test001() {
		CalculateService service = new CalculateService();
		service.setValue1(100);
		service.setValue2(50);
		service.setOperation(Operation.ADD);
		service.calculate();
		assertThat(service.getResult(), is(150f));
		MockObjectManager.assertCalled(CalculateService.class, "calculate");
		
		MockObjectManager.setReturnValueAtAllTimes(CalculateService.class, "getResult", 777f);
		service.calculate();
		assertThat(service.getResult(), is(777f));
	}
}
```
###build.xml
build.xmlはEclipseのエクスポート機能で原形を作成し、djUnitのタスクを追加しています。
djunitタスクの「usenoverify="true"」はJava8で実行する際に必要です。

```xml:build.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="coverage.report" name="testproject">
    <taskdef classpath="./test/lib/djunit.jar" resource="djunittasks.properties"/>
    
    <property environment="env"/>
    <property name="ECLIPSE_HOME" value="../../eclipse/eclipse/"/>
    <property name="src.main" value="./src/main/java"/>
    <property name="test.src.main" value="./test/src/main/java"/>
    <property name="junit.output.dir" value="junit"/>
    <property name="debuglevel" value="source,lines,vars"/>
    <property name="target" value="1.8"/>
    <property name="source" value="1.8"/>
    <path id="testproject.classpath">
        <pathelement location="bin"/>
        <pathelement location="test/lib/ant-junit4.jar"/>
        <pathelement location="test/lib/asm-3.1.jar"/>
        <pathelement location="test/lib/asm-attrs-1.5.3.jar"/>
        <pathelement location="test/lib/jakarta-oro-2.0.7.jar"/>
        <pathelement location="test/lib/jcoverage-djunit-1.0.5.jar"/>
        <pathelement location="test/lib/djunit.jar"/>
        <pathelement location="test/lib/junit.jar"/>
        <pathelement location="test/lib/hamcrest-core-1.3.jar"/>
    </path>
    <target name="init">
        <mkdir dir="bin"/>
        <copy includeemptydirs="false" todir="bin">
            <fileset dir="src/main/java">
                <exclude name="**/*.launch"/>
                <exclude name="**/*.java"/>
            </fileset>
        </copy>
        <copy includeemptydirs="false" todir="bin">
            <fileset dir="test/src/main/java">
                <exclude name="**/*.launch"/>
                <exclude name="**/*.java"/>
            </fileset>
        </copy>
    </target>
    <target name="clean">
        <delete dir="bin"/>
    </target>
    <target depends="clean" name="cleanall"/>
    <target depends="build-subprojects,build-project" name="build"/>
    <target name="build-subprojects"/>
    <target depends="init" name="build-project">
        <echo message="${ant.project.name}: ${ant.file}"/>
        <javac debug="true" debuglevel="${debuglevel}" destdir="bin" includeantruntime="false" source="${source}" target="${target}">
            <src path="src/main/java"/>
            <src path="test/src/main/java"/>
            <classpath refid="testproject.classpath"/>
        </javac>
    </target>
    <target description="Build all projects which reference this project. Useful to propagate changes." name="build-refprojects"/>
    <target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler">
        <copy todir="${ant.library.dir}">
            <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/>
        </copy>
        <unzip dest="${ant.library.dir}">
            <patternset includes="jdtCompilerAdapter.jar"/>
            <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/>
        </unzip>
    </target>
    <target description="compile project with Eclipse compiler" name="build-eclipse-compiler">
        <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
        <antcall target="build"/>
    </target>
    <target name="HelloServiceTest" depends="build">
        <mkdir dir="${junit.output.dir}"/>
        <djunit printsummary="withOutAndErr" targetsrcdir="${src.main};${test.src.main}" virtualmock="yes" coverage="no" usenoverify="true">
            <formatter type="xml"/>
            <test name="com.example.HelloServiceTest" todir="${junit.output.dir}"/>
            <jvmarg line="-ea"/>
            <classpath refid="testproject.classpath"/>
        </djunit>
    </target>
    <target name="CalculateServiceTest" depends="build">
        <mkdir dir="${junit.output.dir}"/>
        <djunit printsummary="withOutAndErr" targetsrcdir="${src.main};${test.src.main}" virtualmock="yes" coverage="no" usenoverify="true">
            <formatter type="xml"/>
            <test name="com.example.CalculateServiceTest" todir="${junit.output.dir}"/>
            <jvmarg line="-ea"/>
            <classpath refid="testproject.classpath"/>
        </djunit>
    </target>
    <target name="TestAll" depends="build">
        <mkdir dir="${junit.output.dir}"/>
        <djunit printsummary="withOutAndErr" targetsrcdir="${src.main};${test.src.main}" virtualmock="yes" coverage="yes" usenoverify="true">
            <formatter type="xml"/>
            <jvmarg line="-ea"/>
            <classpath refid="testproject.classpath"/>
            <batchtest todir="${junit.output.dir}">
                <fileset dir="./bin">
                    <include name="**/*Test.class"/>
                </fileset>
            </batchtest>
        </djunit>
    </target>
    <target name="coverage.report" depends="TestAll">
        <djunit-coverage-report serFile="./jcoverage.ser" srcdir="${src.main}" destdir="${junit.output.dir}">
            <classpath refid="testproject.classpath"/>
        </djunit-coverage-report>
    </target>
</project>

```

##実行
Eclipse、あるいはコマンドラインから実行できます。ただし、test/libにコピーしたant-junit4.jarのバージョンと同じAntを使ってください。以下にコマンドラインから実行した結果を記します。
![Screenshot from 2019-08-25 22-07-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132879/b09f953f-0b45-5b73-b18a-d5a455c991f9.png)

###カバレッジレポート
カバレッジレポートも作成されるんですが、なんか変なんですよね・・・
![Screenshot from 2019-08-25 22-14-25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132879/076e8a01-f29c-299a-5acd-54c18c6fb9aa.png)
![Screenshot from 2019-08-25 22-15-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132879/636bebb3-89fe-a14a-56b1-e82093f00af9.png)

##まとめ
古いからかdjUnitの情報が少ないのでこの記事を書きました。
修正すべき箇所等あるかと思いますので、何か気づきましたらご指摘いただければ幸いです。

##追記 2019/8/27
Eclipseでリモートデバッグする方法です。
build.xmlのdjunitタスクのjvmargを以下のようにします。-eaはなくてもかまいません。

```xml:build.xml
<jvmarg line="-ea -agentlib:jdwp=transport=dt_socket,suspend=y,server=y,address=8000"/>
```

実行すると以下のように途中で停止します。
![Screenshot from 2019-08-27 22-21-44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132879/65b113cf-cf28-475e-3df6-4c6ced7e0e25.png)
続いてEclipseからtestprojectを選択して［右クリック］→［デバッグ］→［デバッグの構成］→［リモートJavaアプリケーション］を選択し、図のように入力したらデバッグボタンを押します。これでデバッグ実行できます。
ブレイクポイントの設定をお忘れなく。
![Screenshot from 2019-08-27 22-22-24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132879/4cbeacd8-ebf8-45d8-543c-996b1ee85265.png)