正式リリース前に Eclipse で JUnit 5を愉しむ

# 概要
Java のテスティングフレームワーク JUnit は今年メジャーバージョンの 5 がリリースされます。先日 San Jose で開催されていた [Eclipse Converge 2017](https://www.eclipseconverge.org/na2017/) というカンファレンスで、この JUnit 5 を Eclipse で使う方法を聞いてきたので、Windows 10 の私物 PC で試してみました。

## JUnit 5
JUnit の5番目のメジャーバージョンです。Java 8 や 9 での新しい言語仕様に対応するため、作り直したとのことです。

### JUnit 4 でカバーしきれなかった新しい言語仕様
- Lambda expression
- Stream API
- Jigsaw

### 参考
JUnit 5 での新機能や注意点については、日本語でもすでに多数の資料が存在していますので、そちらをご参照ください。

- ["Java Magazine vol.30" 特集記事「初めてのJUnit 5」](http://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-ND16-JUnit5Overview.pdf)

## 環境
JUnit 5 は Eclipse 4.7.0(Oxygen) の Milestone 6 からβサポートするとのことでした。下記からダウンロードできます。

https://eclipse.org/downloads/packages/release/Oxygen/M6

なお、この記事を書いている 2017/04/05 時点では 4.7.x の日本語化プラグインはないようです。

http://mergedoc.osdn.jp/

その他の環境は下記の通りです。

| OS | Windows 10
|:---|:---
| Java SE | 1.8.0_121
| Eclipse | 4.7.0-M6
| git     | 2.12.2.windows.1

----
# 導入
JUnit 5 用の Eclipse プラグインをソースコードから作成して、お使いの Eclipse(4.7系)にインストールします。

https://wiki.eclipse.org/JDT_UI/JUnit_5 の手順に従い進めます。なお、ファイルのダウンロードに git が必要です。もちろん Eclipse もいります。Eclipse は Java のものをダウンロードしていれば特に問題はないと思います。"for Testers" をダウンロードしていた場合はプラグイン開発ツールを別途インストールしておいてください。
プラグインのビルドは Eclipse で実施するため、Ant や Maven や Gradle は不要です。

## プラグイン開発用ワークスペースの準備
必須ではありませんが、まあ、通常の開発用ワークスペースと混ぜたくないと思いますので用意しておくとよいでしょう。

## https://github.com/noopur2507/eclipse-junit5.git をチェックアウト
特にファイルのビルドは必要ないので、 https://github.com/noopur2507/eclipse-junit5/archive/master.zip をダウンロードしてくればよいです。その場合、```eclipse-junit5-master.zip``` というファイルがダウンロードされます。この zip ファイルの中身は、それぞれ下記の通り import & 配置してください。

- org.eclipse.jdt.junit5.runtime をプラグイン開発用ワークスペースに import
- JUnit-5-JARs の jar を dropins に配置

### JUnit-5-JARs の jar を dropins に配置

![ju5_1.png](https://qiita-image-store.s3.amazonaws.com/0/102004/1adfaea0-445b-a3f7-c97a-1fa04551036e.png)

![ju5_9.png](https://qiita-image-store.s3.amazonaws.com/0/102004/691955c5-8f73-4ded-3a3d-7e2ce592ac36.png)


## git://git.eclipse.org/gitroot/jdt/eclipse.jdt.ui.git を clone する
git を使って clone してください。特に鍵の設定は要りません。なお、全部ダウンロードするのに10分以上かかります。

```
$ git clone git://git.eclipse.org/gitroot/jdt/eclipse.jdt.ui.git
Cloning into 'eclipse.jdt.ui'...
remote: warning: ignoring extra bitmap file: objects/pack/pack-dffcdea022429c2393e25dfe14e4b833fb5d7dd0.pack
remote: Counting objects: 474929, done.
remote: Compressing objects: 100% (715/715), done.

remote: Compressing objects: 100% (715/715), done.
remote: Total 474929 (delta 364), reused 0 (delta 0)
Receiving objects: 100% (474929/474929), 73.43 MiB | 125.00 KiB/s, done.
Resolving deltas: 100% (249502/249502), done.
Checking out files: 100% (12727/12727), done.
```

clone し終わったら移動してください。

```
$ cd eclipse.jdt.ui
```

### BETA_JUNIT5 ブランチに切り替え

```
eclipse.jdt.ui $ git checkout -b BETA_JUNIT5
Switched to a new branch 'BETA_JUNIT5'
```

### origin の BETA_JUNIT5 を pull

```
eclipse.jdt.ui $ git pull origin BETA_JUNIT5
From git://git.eclipse.org/gitroot/jdt/eclipse.jdt.ui
 * branch                  BETA_JUNIT5 -> FETCH_HEAD
Auto-merging org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JunitPreferenceInitializer.java
Merge made by the 'recursive' strategy.
 org.eclipse.jdt.junit.core/plugin.properties       |   3 +-
 org.eclipse.jdt.junit.core/plugin.xml              |  13 +-
 .../jdt/internal/junit/JUnitCorePlugin.java        |   5 +-
 .../eclipse/jdt/internal/junit/JUnitMessages.java  |  10 +-
 .../jdt/internal/junit/JUnitMessages.properties    |   6 +-
 .../internal/junit/JUnitPreferencesConstants.java  |  38 ++-
 .../internal/junit/JunitPreferenceInitializer.java |  24 +-
 .../internal/junit/buildpath/BuildPathSupport.java |  90 ++++++-
 .../junit/buildpath/JUnitContainerInitializer.java |  59 ++++-
 .../internal/junit/launcher/JUnit5TestFinder.java  | 286 ++++++++++++++++++++
 .../JUnitLaunchConfigurationConstants.java         |   5 +-
 .../internal/junit/launcher/TestKindRegistry.java  |  12 +-
 .../internal/junit/model/ITestRunListener2.java    |  16 +-
 .../eclipse/jdt/internal/junit/model/IXMLTags.java |  16 +-
 .../junit/model/RemoteTestRunnerClient.java        |   2 +-
 .../jdt/internal/junit/model/TestCaseElement.java  |  12 +-
 .../jdt/internal/junit/model/TestElement.java      |  55 +++-
 .../eclipse/jdt/internal/junit/model/TestRoot.java |   4 +-
 .../jdt/internal/junit/model/TestRunHandler.java   |  14 +-
 .../jdt/internal/junit/model/TestRunSession.java   | 107 ++++++--
 .../junit/model/TestRunSessionSerializer.java      |  28 +-
 .../jdt/internal/junit/model/TestSuiteElement.java |  12 +-
 .../internal/junit/util/CoreTestSearchEngine.java  |  60 ++++-
 .../src/org/eclipse/jdt/junit/JUnitCore.java       |  10 +-
 .../launcher/JUnitLaunchConfigurationDelegate.java | 107 ++++++--
 org.eclipse.jdt.junit.runtime/META-INF/MANIFEST.MF |   8 +-
 .../junit/runner/FirstRunExecutionListener.java    |   4 +-
 .../jdt/internal/junit/runner/ITestIdentifier.java |   5 +-
 .../jdt/internal/junit/runner/ITestLoader.java     |   5 +-
 .../internal/junit/runner/IVisitsTestTrees.java    |   4 +-
 .../jdt/internal/junit/runner/MessageIds.java      |  24 +-
 .../internal/junit/runner/RemoteTestRunner.java    |  81 ++++--
 .../jdt/internal/junit/runner/TestIdMap.java       |   2 +-
 .../junit/runner/TestReferenceFailure.java         |   7 +-
 .../junit/runner/junit3/JUnit3Identifier.java      |  10 +-
 .../junit/runner/junit3/JUnit3TestLoader.java      |   4 +-
 .../junit/runner/junit3/JUnit3TestReference.java   |  22 +-
 org.eclipse.jdt.junit/plugin.xml                   |  11 +-
 .../junit/buildpath/JUnitContainerWizardPage.java  |  19 +-
 .../junit/ui/JUnitClasspathFixProcessor.java       |  38 ++-
 .../jdt/internal/junit/ui/JUnitMessages.java       |  12 +-
 .../jdt/internal/junit/ui/JUnitMessages.properties |  10 +-
 .../eclipse/jdt/internal/junit/ui/JUnitPlugin.java |  53 +++-
 .../internal/junit/ui/JUnitQuickFixProcessor.java  |  47 +++-
 .../junit/ui/JUnitUIPreferencesConstants.java      |  18 +-
 .../jdt/internal/junit/ui/OpenTestAction.java      |  30 ++-
 .../jdt/internal/junit/ui/TestRunnerViewPart.java  |  21 +-
 .../junit/ui/TestSessionLabelProvider.java         |  45 ++--
 .../eclipse/jdt/internal/junit/ui/TestViewer.java  | 152 ++++++++---
 .../jdt/internal/junit/util/JUnitStubUtility.java  |   8 +
 .../junit/wizards/NewTestCaseCreationWizard.java   |  69 +++--
 .../junit/wizards/SuiteClassesContentProvider.java |   4 +-
 .../jdt/internal/junit/wizards/WizardMessages.java |   7 +-
 .../junit/wizards/WizardMessages.properties        |   9 +-
 .../launcher/JUnitLaunchConfigurationTab.java      |  27 +-
 .../jdt/junit/launcher/JUnitLaunchShortcut.java    |  48 ++--
 .../junit/wizards/NewTestCaseWizardPageOne.java    | 290 ++++++++++++++++-----
 .../jdt/junit/wizards/NewTestSuiteWizardPage.java  |   4 +-
 .../internal/junit4/runner/JUnit4Identifier.java   |  10 +-
 .../internal/junit4/runner/JUnit4TestLoader.java   |   3 +-
 .../junit4/runner/JUnit4TestReference.java         |   6 +-
 .../corext/codemanipulation/StubUtility.java       |   2 +-
 .../templates/default-templates.properties         |   4 +-
 org.eclipse.jdt.ui/templates/default-templates.xml |  15 +-
 64 files changed, 1728 insertions(+), 404 deletions(-)
 create mode 100644 org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/JUnit5TestFinder.java
```

こちらのコードもMaven等のビルドツールでビルドする必要はありません。更新されたフォルダ群から、下記5つをプラグイン開発用ワークスペースに import してください。

1. org.eclipse.jdt.ui
2. org.eclipse.jdt.junit
3. org.eclipse.jdt.junit.core
4. org.eclipse.jdt.junit.runtime
5. org.eclipse.jdt.junit4.runtime

![ju5_4.png](https://qiita-image-store.s3.amazonaws.com/0/102004/8b415394-e8e1-57b1-ab0c-f14ef784e319.png)
![ju5_5.png](https://qiita-image-store.s3.amazonaws.com/0/102004/43315cab-d870-a1a5-9ce0-90d373baa95c.png)
![ju5_6.png](https://qiita-image-store.s3.amazonaws.com/0/102004/2a0fc1be-15db-0947-00c3-f233b1694e6f.png)
![ju5_8.png](https://qiita-image-store.s3.amazonaws.com/0/102004/21ed1548-42ae-bf0a-2f17-462aae65405b.png)
![ju5_7.png](https://qiita-image-store.s3.amazonaws.com/0/102004/5800e2c8-3ade-e54e-31d3-39e08b8b96d8.png)


## プラグインのエクスポートとインストール
Eclipse のメニューバーから「ファイル」→「エクスポート」→「プラグイン開発(Plug-in Development)」の "Deployable plug-ins and fragments" を選択します。当然ですが、プラグイン開発ツールが入っていないと選択肢が出てきません。Test Developer 版を入れている場合は注意してください。

![ju5_10.png](https://qiita-image-store.s3.amazonaws.com/0/102004/6307ec3a-8052-5ab4-5b44-652bb3139eaa.png)

![ju5_11.png](https://qiita-image-store.s3.amazonaws.com/0/102004/53426cde-d110-f47b-2ced-aa9e3b8970b1.png)

"Install into host. Repository:" under "Destination" チェックボックスにチェックを入れている場合、プラグインのエクスポートが終了次第、続けてプラグインのインストールを始めます。インストールが終わると Eclipse が再起動を求めてくるので再起動しましょう。

Windows の場合、もし Eclipse を C ドライブに置いていてランチャーが消えてしまった場合は、手間ですが再度 Eclipse をダウンロードして exe ファイルだけを eclipse フォルダにコピーしましょう。

## 確認
新規の Java プロジェクトを作成し、ビルドパスの設定を開いて、ライブラリの追加で JUnit を選択します。プラグインが正常にエクスポート＆インストールされていれば、ここで出るダイアログの選択肢に JUnit 5 が追加されているはずです。

![ju5_12.png](https://qiita-image-store.s3.amazonaws.com/0/102004/6c5b1c87-5b5e-2196-30da-bcd62061d913.png)

これで Eclipse 上で JUnit 5 の開発ができるようになりました。

----
# JUnit 5 を愉しむ
では、試しに JUnit 5 のコードを書いて動かしてみましょう。今回は JUnit 5 の新機能 Group assertion を試すコードを書いてみます。

```java:JUnit_5_Example
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class BaseTest {

	@Test
	public void test() {
		Assertions.assertEquals(Integer.valueOf(1).toString(), "1");
		Assertions.assertAll(
				() -> Assertions.assertEquals(Integer.valueOf(1).toString(), "1"),
				() -> Assertions.assertEquals(Integer.valueOf(1).toString(), "2"),
				() -> Assertions.assertEquals(Integer.valueOf(3).toString(), "3"),
				() -> System.out.println("Hello JUnit5!")
				);
	}
}
```

JUnit 4 までと同じように動かせます。

![ju5_13.png](https://qiita-image-store.s3.amazonaws.com/0/102004/9c9b70a8-cec7-1ae0-d3df-074648fd8c40.png)

はい、2番目の Assertion が fail なのでテストは失敗します。ここで注目してほしいのは、コンソールに "Hello JUnit5!" と出力されている点です。従来の JUnit では、1つのテストメソッド内で assertion が fail した場合、以降の処理は一切実行されませんでした。JUnit 5 の Group assertion では、その Group 内の処理は必ず実行されるようになっています。

これで、今回エクスポートした JUnit 5 用プラグインが正常に動作することを確認できました。ここまで3時間ほどかかりました。

----
# まとめ
まだ結構面倒ですので、業務で JUnit 5 をプロジェクトに導入したいのであれば、よほどの理由がない限り、Eclipse が JUnit 5 に正式対応するまで待つか、IntelliJ を使いましょう……

あるいは、Gradle や Maven プラグイン経由で使うのが良いと思います。

----
# 参考

## JUnit 5 User Guide
http://junit.org/junit5/docs/current/user-guide/

## Eclipse Converge 2017 のセッション "Embracing JUnit 5 with Eclipse"
- セッション紹介：[Embracing JUnit 5 with Eclipse](https://www.eclipseconverge.org/na2017/session/embracing-junit-5-eclipse)
- 資料(PDF)：[Embracing JUnit 5 with Eclipse](https://www.eclipseconverge.org/na2017/sites/default/files/slides/Embracing%20JUnit%205%20with%20Eclipse.pdf) 

## Gradle での JUnit 5 サンプルプロジェクト
https://github.com/junit-team/junit5-samples/tree/r5.0.0-M4/junit5-gradle-consumer

## Maven での JUnit 5 サンプルプロジェクト
https://github.com/junit-team/junit5-samples/tree/r5.0.0-M4/junit5-maven-consumer