*

Eclipse Oxygen Update 1 (4.7.1)を利用してJUnit5の公式ガイドの内容を実践してみる。

公開日: : 最終更新日:2017/11/05 Eclipse, Java, JUnit , ,


スポンサードリンク



いよいよJUnit5が本格的に利用できる環境が整ってきました。

本エントリーでは「Eclipse Oxygen Update 1 (4.7.1) 」を利用し、
JUnit5の公式ガイド「JUnit 5 User Guide」の内容をより実践的で、読んで理解できるようにした内容となります。

「Pleiades All in One」も4.7.1に対応したプロダクトがリリースされていますが、
Mac環境でJUnit5を利用すると異常終了するので、オリジナルのEclipseを前提に説明させていただきます。
(私の環境の問題かもしれませんので、Mac使いの方で正常に動作する方がいればコメントいただければ幸いです。)

本エントリーの内容は以下の通りです。

  1. JUnit5で利用できるAnnotation
  2. 実際の利用方法

 

1 JUnit5のAnnotation

JUnit4もある段階からアノテーションベースのプロダクトとなっており、
アノテーションこそが肝であると言えます。

JUnit5も同様で、アノテーションベースのプロダクトとなっています。

利用可能なアノテーションの概要は以下の通りです。

アノテーション 説明
@Test テストメソッドに付与
@ParameterizedTest JUnit4のorg.junit.runners.Parameterizedに相当、パタメータで指定を変更してテストを実行することができます。
@RepeatedTest テストを繰り返し実行したいときに利用します。
@TestFactory 動的テスト機能を利用するときに指定します。実行時にテストを生成し実行します。
@TestInstance テストクラスのライフサイクルを指定できます。指定しない場合はJUnit4と同様にテストメソッド毎にインスタンスが生成されます。
@TestTemplate @DisplayName テストの表示名称を指定します。
@BeforeEach 各テストメソッドの実行前に呼び出したいメソッドに付与します。JUnit4の@Before相当です。
@AfterEach 各テストメソッドの実行後に呼び出したいメソッドに付与します。JUnit4の@After相当です。
@BeforeAll 任意のテストクラスの実行前に呼び出したいstaticメソッドに付与します。JUnit4の@BeforeClass相当です。
@AfterAll 任意のテストクラスの実行後に呼び出したいstaticメソッドに付与します。JUnit4の@AfterClass相当です。
@Nested ネストされたstaticでないテストクラスであることを示します。@BeforeAllメソッドと@AfterAllメソッドは@Nestedテストクラスでは使用できません。
@Tag テストのフィルタリングをするためのタグを指定します。JUnit4のCategoriesに相当します。
@Disabled テストを無効化するときに付与します。JUnit 4の@Ignoreに相当します。
@ExtendWith カスタム拡張を登録するために利用します。

 

2 実際の利用方法

プロジェクトの作成とライブラリの追加

プロジェクトを作成します。

プロジェクト名にJUnit5Sampleと入力し「Finish」をクリックします。

次にJUnit5のライブラリの参照を追加します。
プロジェクトを選択して、マウスの右クリックメニューの「Properties」をクリックします。

「Libraries」タブの「Add Library…」ボタンをクリックします。

「JUnit」を選択し「Next>」をクリックします。

「JUnit5」が選択されていることを確認後に「Finish」をクリックします。

「Apply and Close」をクリックします。

これで準備OKですが、テストケースのクラス生成時にEclipseがライブラリを追加するか聞いてくるので
事前に追加しておかなくてもOKですが・・・

テストの実装の基本

プロジェクトを選択して、マウスの右クリックメニューの「JUnit Test Case」をクリックします。

NameにFirstJUnit5Testsと入力し「Finish」をクリックします。

生成されたファイルの中身を以下のように書き換えます。

公式のサンプルとまった同じです。
この例ではassertEqualsを利用して、「1+1は2になる」との検証を行っています。

FirstJUnit5Testsを実行すると、@Testが付与されたmyFirstTestがUnitで実行されます。

実行後の画面は以下のようになります。JUnitのお決まりのテストが成功すればグリーンバー、失敗すればレッドバーになるとの仕様となります。

@BeforeAll、@BeforeEach、@AfterEach、@AfterAll

@BeforeAll、@BeforeEach、@AfterEach、@AfterAllの各アノテーションの利用例は以下のようになります。

テストメソッドはsucceedingTestとfailingTestですので
実行するとEclipseのコンソールに以下の文字列が表示されます。

コンソールが表示されていない場合は
Eclipseのメニューの「Window」-「Show View」-「Console」をクリックすると表示できます。

@DisplayName

@DisplayNameの利用例は以下のようになります。

実行すると結果は以下のようになります。

@DisplayNameでDisplayNameが指定されているテストは指定値が、指定されていない場合はテストメソッド名が表示されていることが確認できます。

@Disabled

プロダクトのコードに対してテストが乖離し、テストを修正することが困難 or テストケース自体が無意味 or 一時的に実行対象から除外したい場合などに、対象のテストメソッドに付与します。

DisplayNameDemo.javaのtestWithDisplayNameContainingSpecialCharactersに@Disabledを付与してみます。

実行結果は以下のようになります。

testWithDisplayNameContainingSpecialCharactersの部分が白いアイコンで表現されています。
また、Runs:の右側が4/4 (1 skipped)とtestWithDisplayNameContainingSpecialCharactersをスキップしたことが見てとれます。

@Tag

利用シーンとしては、@TagでPTとITを指定しておいて、よし!、PTだけ実行する
ことが考えられます。公式ではFASTとSLOW(明示的にこの文言はないですが)が例としてあげられていますが・・・

@Tag(“model”)
@Tag(“dao”)
@Tag(“service”)
@Tag(“controller”)
なんかも付与しておくと色々便利かと思います。

利用例は以下の通りです。

Eclipseでタグを指定して実行するには
プロジェクトを選択して、マウスの右クリックメニューの「Run As」-「Run Configurations..」をクリックします。

実行対象のパッケージ(本例ではdefault package)を選択し、「Test」タグにある「Configure..」ボタンをクリックします。

「Include Tags」をチェックし、実行したいタグをその下のテキストボックスに入力し「OK」をクリックします。

最後に「Run」をクリックします。

タグ:fastを指定したので、@Tag(“fast”)が付与されているTaggingDemoクラスが実行されました。

今度はテストメソッドに付与されているタグを指定して実行してみます。
先ほどと同様の操作でsalariesを指定して実行すると以下のような結果となります。

うんうん、ちゃんと指定したタグが付与されたテストメソッドだけが実行されました。

今回の例では単一のタグ指定の例だけですが、「Include Tags」、「exclude Tags」ともに複数の値が指定可能ですので
GradleとCIツールを併用してテストを定期的に実行する環境を構築する際にはとても便利だと言えます。

メタアノテーションを作成し利用することでタグの付与が楽になります。

@TestInstance

テストクラスのライフサイクルを指定できます。
指定可能な値はLifecycle.PER_CLASSとLifecycle.PER_METHODの2つです。

@TestInstanceを指定しない場合は、Lifecycle.PER_METHODがデフォルトで、メソッド毎にテストクラスのインスタンスが生成されます。

StandardTests.javaにどのインスタンスが利用されているかが分かるようにhashCodeの出力を追加してみます。

実行するとコンソールに以下の内容が表示されました。

succeedingTest実行時のインスタンスのハッシュコードは1486371051
failingTest1497973285実行時のインスタンスのハッシュコードは1497973285
と出力されており、Lifecycle.PER_METHODのライフサイクルで動作していることが見てとれます。

今度は@TestInstance(Lifecycle.PER_CLASS)をクラスに付与してみます。

実行結果は以下のようになりました。

succeedingTest実行時のインスタンスのハッシュコード
failingTest1497973285実行時のインスタンスのハッシュコード
はともに655381473と出力されており、Lifecycle.PER_CLASSのライフサイクルで動作していることが見てとれます。

@Nested

字面通りネストしたテストを作成するときに利用します。

@Nestedの例は以下の通りです。

実行結果は以下の通りです。

コンソールの出力内容は以下の通りです。

returnElementWhenPeekedだけにフォーカスしてみると

となっており、
ルート(TestingAStackDemo)の@BeforeAll
ネスト1階層目(WhenNew)の@BeforeEach
実際のテスト対象クラス(AfterPushing)の@BeforeEach
テスト対象メソッド
ルート(TestingAStackDemo)の@AfterEach
ルート(TestingAStackDemo)の@AfterAll
との順番で呼び出されていることが見てとれます。

@RepeatedTest

繰り返し同じテストを実行したいときに利用します。

@RepeatedTestの利用例は以下の通りです。

繰り返し実行されていることを確認するために@TestInstance(Lifecycle.PER_CLASS)をテストクラスに付与し
テストメソッドでrepeatedCounterをインクリメント、標準出力にrepeatedCounterを出力しています。
(staticなカウンタ追加で確認できるので余分なステップが多いですね・・・)

実行時のコンソールの出力は以下の通りです。

うんうん、繰り返し実行されていますね。
上記の例ではrepeatedCounterとのインスタンスメンバを用意して、実行回数をカウントしましたが、JUnitがこの部分を用意してくれています。

@RepeatedTestでname属性を利用し、name内に {displayName}、{currentRepetition}、{totalRepetitions}を埋め込むことで
実現可能です。

{displayName}は、@DisplayNameで指定したDisplayName
{currentRepetition}は、現在の実行回数
{totalRepetitions}は、@RepeatedTestのvalueで指定した値
がそれぞれ展開されます。

実装例は以下の通りです。

実行結果は以下の通りです。

実行時のコンソールの出力は以下の通りです

@ParameterizedTest

@ParameterizedTestは
Parameterized tests are currently an experimental featureで、
まだ実験的な位置づけとなりますので、今後拡張されていくようです。

@ValueSource

@ParameterizedTestと@ValueSourceを合わせて付与することで
String, int, long, doubleの単一パラメータのみテストが実装可能となります。

@ParameterizedTestと@ValueSourceの利用例は以下の通りです。

実行結果は以下の通りです。

実行時のコンソールの出力は以下の通りです

実行結果に表示されるテストケースの文言が、引数のパラメタとなるので可読性としては良くありません。
@ParameterizedTestのnameで表示される文言を指定することで解消できます。

実行結果は以下の通りです。

@EnumSource

@ParameterizedTestのnameで指定できる埋め込み文字列は
{index} the current invocation index (1-based)
{arguments} the complete, comma-separated arguments list
{0}, {1}, …​: an individual argument
となります。

{0}, {1}, …​は@CsvSourceのところで利用例をあげさせていただきます。

@CsvSource

@ValueSourceの各パラメタの要素がStringのCSVになったアノテーションとなります。

利用例は以下の通りです。

実行結果は以下の通りです。

@ParameterizedTestのnameで指定している{0}にパラメタCSVの第一要素が、{1}に第二要素が展開されていることが確認できます。

カンマを含んだ文字列を指定したい場合は以下のように指定します。

@CsvFileSource

CSVファイルを指定できるアノテーションです。

利用例は以下の通りです。

実行するまえにsrc直下にtwo-column.csvファイルを以下の内容で作成しておきます。

実行結果は以下の通りです。

うんうん、CSVファイルの中身をパラメタとしたテストが実行されていることが確認できました。

ちょっと脇道にそれますが、@CsvFileSourceや@CsvSourceを利用して
パラメタをクラスにマッピングすれば、テストコードの実装時の生産性向上に大きく寄与すると思いますので、簡単な例を作成してみました。

CsvTestData.javaは以下の通りです。

csvtestdata.csvの中身は以下の通りです。

CSVにフィールド名=値とのデータを作成しておき、リフレクションでインスタンス生成と値のセットを行い
生成したインスタンスに対して検証を行っています。

リフレクション部分を共通化すれば実際の業務でも利用できると思います。
少しだけきれいにしてみました。

@EnumSource

名前のとおりですが、Enumをパラメタに指定してテストを実行するときに利用します。

一番シンプルな利用例は以下の通りです。

実行結果は以下の通りです。

TimeUnitで定義されている全ての値を引数としてテストが実行されていることが確認できます。

特定の値だけのテストの例は以下の通りです。

testWithEnumSourceIncludeが”DAYS”, “HOURS”だけを指定したテストメソッド
testWithEnumSourceExcludeが”DAYS”, “HOURS”以外の値を指定したテストメソッド
となります。

testWithEnumSourceIncludeの実行結果は以下の通りです。

testWithEnumSourceExcludeの実行結果は以下の通りです。

@ArgumentsSource

ArgumentsProviderインターフェースを実装したクラスを@ArgumentsSourceで指定することで、テストデータの再利用性を高めることができます。

利用例は以下の通りです。

実行結果は以下の通りです。

@TestFactory

Javaには、C#のデリゲートやRubyのブロックなどに相当する考え方が存在しないので、JUnit4以前では、コンパイル時にテストメソッドを確定する必要がありました。
(イマイチな言い回しですね・・・)

@TestFactoryを利用すればコンパイル時ではなく、実行時までテストメソッドの確定を遅延させることができます。
逆にコンパイルは通るけど、前提条件に依存せずに。絶対に失敗すテストを書くこともできます。

@TestFactoryをうまく利用するとテスト実装時の生産性が格段に向上すると言えます。
テストしている内容の見通しが悪くなるので、複雑なテストには不向きであるとも言えます。

@TestFactoryの利用例は以下の通りです。

dynamicTestsWithInvalidReturnTypeが全体に失敗する例となります。
失敗の理由は

だそうです。

実行結果は以下の通りです。

実際には何に使うねん!、と思い例を考えてみました。
ユニットテスト時にはよくはprivateメソッドをリフレクション経由で参照したり、更新したりしますよね。

このような時に、対象クラスのフィールド名をリテラルでテストに埋め込むのが嫌なので、対象クラスにフィールド名を保持するメンバを設けることにしています。

例としては以下のようになります。

これぐらいだったらgetter、setter書けよ!!
って思うのですが、例ですので・・・

このFIELD_NAME_IDとFIELD_NAME_PASSWORDに定義している文字列に対応するフィールドが存在しているか、とのテストを@TestFactoryを利用して実装してみました。

実行結果は以下の通りです。

うんうん、ダイナミックなテストの感じがまあまあ出ている例になったのではないでしょうか。

@ExtendWtih

@ExtendWtihを利用すると色々テストを拡張できます。
@ExtendWtihで拡張インターフェースを指定することでテストの動作を拡張可能です。

@ExtendWtihで指定可能なインターフェース

JUnit5が提供している拡張インターフェースは以下の通りです。

拡張インターフェース メソッド 戻り値の型 説明
ExecutionCondition evaluateExecutionCondition(ExtensionContext) ConditionEvaluationResult テストの実行可否の判断する
BeforeAllCallback beforeAll(ContainerExtensionContext) void @BeforeAllの前に実行される
BeforeEachCallback beforeEach(TestExtensionContext) void @BeforeEachの前に実行される
BeforeTestExecutionCallback beforeTestExecution(TestExtensionContext) void テストメソッドの前に実行される
AfterTestExecutionCallback afterTestExecution(TestExtensionContext) void テストメソッドの後に実行される
AfterEachCallback afterEach(TestExtensionContext) void @AfterEachの後に実行される
AfterAllCallback afterAll(ContainerExtensionContext) void @AfterAllの後に実行される
TestInstancePostProcessor postProcessTestInstance(Object, ExtensionContext) void テストクラスのインスタンス生成後に実行される
TestExecutionExceptionHandler handleTestExecutionException(TestExtensionContext, Throwable) void テスト時に発生した例外の扱いを決定する
ParameterResolver supports(ParameterContext, ExtensionContext) boolean
ParameterResolver resolve(ParameterContext, ExtensionContext) Object

 

ExecutionCondition

ExecutionConditionの利用例として、今日が1日だったらテストを実行し、それ以外は実行しない例を作成してみました。

ExecutionConditionの実装クラスは以下の通りです。

@ExtendWith(MonthlyExecutionCondition.class)を付与するクラスは以下の通りです。

上記の例ではクラスに@ExtendWith(MonthlyExecutionCondition.class)
を付与していますが、メソッドにも付与できます。

実行結果は以下の通りです。

今日は1日ではないのでテストが実行されませんでした。実行結果のtestContainerExecutionConditionは白いアイコンで表現されており、@Disabledと同様の結果となりました。

BeforeAllCallback, BeforeEachCallback, BeforeTestExecutionCallback,AfterTestExecutionCallback, AfterEachCallback, AfterAllCallback

「@ExtendWtihで指定可能なインターフェース」で記載させていただいた通りですが、任意のタイミングで処理を行いたい場合に利用します。

各インターフェースを利用する例は以下の通りです。

各インターフェースの実装クラスは以下の通りです。
標準出力にクラス名.実装インターフェースのメソッドを出力しているだけですが・・・

実行時のコンソール出力は以下の通りです。

うんうん、予想どうりの結果ですね!


スポンサードリンク



関連記事

Eclipse4.4,4.3の使い方[エディタのフォントサイズの変更方法]

今回は、Eclipse4.4と,4.3におけるエディタエリアのフォントサイズの変更方法を説明させてい

記事を読む

JUnit入門その9[@RunWithアノテーションを利用したテストの作成]

今回は@RunWithアノテーションを利用したテストの作成方法を説明させていただきます。 JU

記事を読む

Selenium入門その6[Selenium3でWebDriver(Java/Junit4)の環境を作成しEdge,Chrome,Firefoxで確認してみる]

Selenium3も3.0.1がリリースされましたし、今後は本格的にSelenium3が利用されてい

記事を読む

Eclipse4.3のチュートリアル機能で”Hello World”アプリケーションの作成方法を説明する。

Eclipseのインストールが終了したので、各画面エリアの名称の説明、各画面エリアの使い方の説明を

記事を読む

Eclipse(4.3)の使い方[パースペクティブのツールバーのカスタマイズ(「ツール・バー可視性」と「メニュー可視性」タブ)]

前回エントリー「Eclipse(4.3)の使い方[各画面エリアの名称とパースペクティブのカスタマイズ

記事を読む

Eclipseの「DBViewer」プラグインを利用して「Java DB」の環境を作成し、SQLを発行してみる

EclipseのJUnitプラグインとDBUnitを併用したDB(データベース)のアクセス処理のユニ

記事を読む

Java超入門 with Eclipse[5:クラスに関する基礎知識(メソッドをJUnitを使って説明)]

クラスに関する基礎知識シリーズも、いよいよメソッドを残すのみとなりました。 前回までは、Eclip

記事を読む

Eclipse4.4(Java)におけるビルド・パス関係の設定方法[ビルド・クラスパスの順序およびエクスポート設定]

Eclipse4.4(Java)におけるビルド関係のビルド・パス上の「ビルド・クラスパスの順序および

記事を読む

Eclipse4.4(Java)におけるビルド・パス関係の設定方法[ビルド・パス上に必要なプロジェクト/プロジェクト参照の追加]

Eclipse4.4(Java)におけるビルド関係のビルド・パス上の「ビルド・パス上に必要なプロジェ

記事を読む

JUnit入門その3[Eclipse4.4のJUnitプラグインとMockフレームワークのJMockitの併用の基本]

JUnit入門その3ではMockフレームワークのJMockitを利用したテスト環境の構築と使い方につ

記事を読む

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Eclipse Oxygen Update 1 (4.7.1)を利用してJUnit5の公式ガイドの内容を実践してみる。

いよいよJUnit5が本格的に利用できる環境が整ってきました。

Spring5入門[簡単なWebアプリのユニットテストをJUnit5とJMockitで作成]

Spring5入門ではJUnit4とmockitを利用したSpring

Spring5入門[STS(Spring Tool Suite)で簡単なWebアプリの典型的なユニットテストの実現方法]

前回は「Spring入門」で、Spring MVCを利用した簡単なWe

Spring5入門[STS(Spring Tool Suite)の環境作成と簡単なWebアプリの作成]

Struts1ももう過去の遺物になり、SAStrutsもEOLとなりも

Selenium入門その6[Selenium3でWebDriver(Java/Junit4)の環境を作成しEdge,Chrome,Firefoxで確認してみる]

Selenium3も3.0.1がリリースされましたし、今後は本格的にS

→もっと見る

Optimization WordPress Plugins & Solutions by W3 EDGE
PAGE TOP ↑