JUnit5の味見

 JUnit5の味見

KAN JAVA PARTY 2017の資料です。
題名詐欺でした。
発表はグダッてましたが、JUnit5のUsersGuideは大体網羅しておりますので、参考にしてみてください。

本資料はJUnit5M4をベースにしておりますがM5での変更点については以下のサイトに記載しております。
http://qiita.com/e-yamane/items/d7fa040158bdafc0f9d2

Aae0ea855eda20ad6481fe3777471e95?s=128

Eiji Yamane

June 24, 2017
Tweet

Transcript

  1. JUnit5の味見 2017.06.24 KANJAVA PARTY 2017 !!!

  2. …のつもりが がっつり食べちゃった

  3. 提供は • 93年からずっとプログラマー • 主にというかほぼJavaプログラマー • たまにアジャイルコーチ的なこともしてる 山根 英次 e_yamane

    yamane.eiji
  4. はじめに • JUnit5のUser Guideを元にJUnit5の説明をしまーす • ならべくちゃんと動かしながらやるよ • JUnit4は知ってる前提で喋ります

  5. お詫び • JUnit5 Milestone 4をベースをベースとしています。正式リリース版とは振る舞いが異なる可能性がありま す • User Guideに無い事もたまにしゃべりまーす •

    英訳はかなり適当なので怪しそうなら原典にあたってね • 私見が多分に含まれていますので怪しそうなら原典を当たってね • とても1時間じゃ終わりません • タイムマネジメントを放棄します • 私が付けた優先順位順に説明させていただきます • アップするスライドはちゃんとした順序で上げる予定です • 多分かなりハイスピードになるので詳しくはお家でゆっくり見てね
  6. 関連URL • JUnit5 Users Guide • http://junit.org/junit5/docs/current/user-guide/ • JUnit5 API

    Reference • http://junit.org/junit5/docs/current/api/ • 今日利用したコード • https://github.com/e-yamane/junit5-study
  7. うんちく • JUnit5は一時開発終了の危機があった • クラウドファウンディングで資金調達を呼びかけてた • 日本の人も結構協力してまーす • http://junit.org/junit4/junit-lambda-contributors.html •

    ここに載ってる人達には感謝してもいいんじゃないかな
  8. 本編いくよ〜

  9. 1.Overview • 包括的に書いてるからコレさえ読んでればOKだよ • さすがにそうではなかったけどね • JUnit5は3つのサブプロジェクトで構成されてるよ • JUnit Platformはテストの実行するための基盤を提供するよ

    • JUnit Jupiterはテスト記述者やエンジン拡張用のAPIを提供してるよ • 一番意識するのはこのサブプロジェクト • JUnit Vintageは、JUnit3やJUnit4のテストをJUnit5のTest Engineで実行するためのTest Engineを提 供するよ • JUnit5はJava8でしか動かないよ。でもそれ以前のバージョンでコンパイルしたコードを テストすること自体はできるよ
  10. 2. Installation • 正式版とマイルストーン版はMaven Centralにあるよ • SnapshotはSonatypeにしかないからね

  11. 2.1. Dependency Metadata 2.1.1. JUnit Platform Group ID Version Artifact

    IDs org.junit.platform 1.0.0-M4 junit-platform-commons JUnit内部の共通ライブラリ。使用禁止 junit-platform-console JUnit5をコンソールから実行するためのランナー junit-platform-console-standalone めんどくさい人用。全部乗せ junit-platform-engine エンジンエンジン用のAPI junit-platform-gradle-plugin GradleでJUnit5を動作させるためのプラグイン junit-platform-launcher IDEや、ビルドツールがJUnitの設定や実行を行うためのAPI junit-platform-runner JUnit4の実行系でJUnit5のテストコードを実行できるようにするライブラリ junit-platform-suite-api テストの設定を記述するアノテーションを定義しているライブラリだよ。 junit-platform-surefire-provider Maven surefire用のライブラリ
  12. 2.1. Dependency Metadata 2.1.2. JUnit Jupiter Group ID Version Artifact

    IDs org.junit.jupiter 5.0.0-M4 junit-jupiter-api テストとテストを拡張するために利用するAPI junit-jupiter-engine Jupiterテストエンジンの本体。実行時だけあればいいよ junit-jupiter-params Parameterized Test用のAPI junit-jupiter-migration-support JUnit4のいくつかのRuleの移行用のライブラリ
  13. 2.1. Dependency Metadata 2.1.3. JUnit Vintage Group ID Version Artifact

    IDs org.junit.vintage 4.12.0-M4 junit-vintage-engine JUnit4またはJUnit3のテストをJunit Platformで実行できるテスト エンジン
  14. 2.2. Dependency Diagram junit-platform-console-standalone

  15. 2.3. JUnit Jupiter Sample Projects • 手っ取り早く動かしたいならここにサンプルがあるよ • Gradle •

    https://github.com/junit-team/junit5-samples/tree/r5.0.0-M4/junit5-gradle-consumer • Maven • https://github.com/junit-team/junit5-samples/tree/r5.0.0-M4/junit5-maven-consumer
  16. 3. Writing Tests

  17. …の前に!! 動かないテストコードはただのゴミなので

  18. 4. Running Tests 4.1. IDE Support • IntelliJ IDEA •

    ここにやり方書いてるよ! • https://blog.jetbrains.com/idea/2016/08/using-junit-5-in-intellij-idea/ • 試してないから分かりません • Eclipse Beta Support • Oxygenからベータサポートしてるよ • ここにやり方書いてあるよ • https://wiki.eclipse.org/JDT_UI/JUnit_5 • かなり、面倒いそしてダメだった…orz • Other IDEs • 今はサポートしてないよ • Console LauncherかJUnit4ベースのRunnerで実行してね
  19. 4. Running Tests 4.2.1. Gradle Support(1) • ごちゃごちゃ書いてあるけど、最終リリースまでに変更される可能性が非 常に高いとのことでまじめに読まなくてもいいです •

    必要最低限の部分をコードで説明しまーす • build.gradle
  20. 4. Running Tests 4.2.1. Gradle Support(2) • テスト実行は「junitPlatformTest」タスクで実行 • 「test」でも実行できるけどね

    • All OKならexit コードは0、それ以外は1 • 現時点では、テスト実行してテスト結果のXMLファイルを作成するだけで テストレポートは出力しません • Jenkinsで見れるよねだって • でも変!!
  21. 4. Running Tests 4.2.2. Maven • 興味が無いのでスキップ

  22. 4. Running Tests 4.3. Console Launcher • 興味が無いのでスキップ

  23. 4. Running Tests 4.4. Using JUnit 4 to Run the

    JUnit Platform • JUnit4のRunnerでJUnit5のテストを動かす方法 • 一番手っ取り早いので、以降は基本的にこの方法でやります • @RunWith(JUnitPlatform.class)と書けば良い • Junit Platformの全機能が使えるわけではないです • 「7. Advanced Topics」以外は問題ありません • 設定方法(内部参照ライブラリ省略) 1. junit(4x)をtestスコープで参照 2. junit-platform-runnerをtest スコープで参照 3. junit-jupiter-apiをtestスコープで参照(JUnit5の記述に必須) 4. junit-jupiter-engineをtestRuntimeスコープで参照
  24. あらためて、3. Writing Tests

  25. …の前に!! まだ、正式リリースではないので。。。

  26. 8.API Evolution • JUnit5のAPIには@APIアノテー ションでAPIの成熟度が表現され ているので成熟度が低い物につ いては変わるものだと思ってくだ さい • JUnitPlatformは「

    Maintained」です Internal 内部での利用を前提。自己責任で Deprecated 非推奨。消えても知らんで Experimental 実験中。消えたり変わったりするかも Maintained 少なくとも現在のメジャーバージョンの次のマ イナーリリースまでは変わらない Stable 現在のメジャーバージョン中は変わらない
  27. やっと、、、3. Writing Tests

  28. 3.Writing Tests • コード見ましょうか • FirstJUnit5Tests.java • テストクラスはpublicじゃなくていいです • テストメソッドもpublicじゃなくていいです

    • publicじゃなくても良くなったのはコード補完で助かるので良いことです • @Testはパッケージが違います • org.junit.jupiter.api
  29. 3.1. Annotations @Test Stable テストメソッドに付けるJUnit4の@Testに有った属性は無くなった(別の方法で実現) @RepeatedTest Experimental 同じテストを複数回繰り返したい場合に付与するアノテーション @TestFactory Experimental

    動的にテストを生成するファクトリとなるメソッドに付与するアノテーション @DisplayName Experimental テストレポート用に名前をつけられるよ(つけられるとは言ってないw) @BeforeEach Stable JUnit4の@Beforeと同じ @AfterEach Stable JUnit4の@Afterと同じ @BeforeAll Maintained JUnit4の@BeforeClassと同じ。staticメソッドとして記述すること @AfterAll Maintained JUnit4の@AfterClassと同じ。staticメソッドとして記述すること @Nested Experimental ネストされた非静的なテストクラスにつける。@Enclosedとはちょっと違う @Tag Maintained JUnit4の@Category的なもの。@Tagsと言うのもある @Disabled Stable JUnit4の@Ignore的なもの @ExtendWith Experimental @Rule/@ClassRuleに変わる拡張点の指定アノテーション
  30. 3.1.1. Meta-Annotations and Composed Annotations • Jupiterのアノテーションはメタ注釈として利用できるよ • JUnit5のアノテーションはアノテーションにアノテートすることができるよ •

    JUnit5のアノテーションをアノテートしたアノテーションをアノテートするとアノテー ションにアノテートしたJUnit5のアノテーションをアノテートしたことと同義と見なす • 訳わかんないよねwコード見ると簡単なんです。 • SlowTest.java • SlowTestTest.java • (JUnit5上で独自のテスティングフレームワーク作る人には)超重要!!
  31. 3.2. Standard Test Class • 単なるサンプルコードで読めば分かるのでスキップ!

  32. 3.3. Display Names(1) • メソッド名やクラス名じゃなくて独自に表示名を変えるためのアノテーション • 時代が俺に追いつきました! • 「Java Press

    Vol 43」(2005/7/15発売)で「テストレポート日本語化計画」とか書いてました • http://gihyo.jp/magazine/javapress/archive/2005/vol43 • …と思ったんだけど • DisplayNameTest.java • DisplayNameForJUnit4Test.java
  33. 3.3. Display Names(2) • Gradleでtestを実行してもテスト結果には反映されません!! • テストこかすと見えます • XMLの<system-out>タグの中に出力されてるだけ •

    当然Jenkinsのテストレポートにも表示されません • JUnitPlatform越しに実行するとちゃんと出る!!
  34. 3.4.Assertions(1) • org.junit.jupiter.api.Assertions(Maintained)配下にあるよ • JUnit4の代替のAPIはあるよ(全部ぢゃないよ)

  35. 3.4.Assertions(2) JUnit4にもあるAssertion • assertArrayEquals • assertEquals/assertNotEquals • assertFalse/assertTrue • BooleanSupplierもOK

    • assertNotNull/assertNull • assertNotSame/assertSame • fail • 浮動小数点のdeltaナシは何故かDeprecatedから通常に昇格(?) • エラーメッセージは第1引数から最終引数に変更。メッセージはラムダで渡せる • エラー発生まで遅延評価されるので正常時に高速にテストが行える • AssertEqualsTest.java
  36. 3.4.Assertions(3) 新API: assertAll • メッセージは第1引数ですw • 複数のテストを一気にやる! • 1つがこけても全部やってくれる •

    エラー報告も全部でる • 良い子 • ちなみに、parallelStream渡すと並列実行できます!! • AssertAllTest.java
  37. 3.4.Assertions(4) 新API: assertIterableEquals • Iterable同士の比較 • IterableだからStreamはできない...

  38. 3.4.Assertions(5) 新API: assertLinesMatch • 文字列のList同士の比較 • 第1引数側に正規表現を渡せば正規表現としてマッチしてるかどうかの 検証もしてくれる • 。。。ん〜Core

    APIレベルでいるか!?
  39. 3.4.Assertions(6) 新API: assertThrows • JUnit4の@Testのexpectedの代替 • assertionの戻り値として発生した例外を受け取れるので、発生した例外の 精査もできるよ • 良い子

    • AssertThrowsTest.java
  40. 3.4.Assertions(7) 新API: assertTimeout/ assertTimeoutPreemptively • JUnit4の@Testのtimeoutの代替 • テストメソッド全体ではなく、検査対象を絞れるのでより厳密にチェックできる • assertTimeoutとassertTimeoutPreemptivelyの違い

    • assertTimeoutはタイムアウトしても検証処理自体は継続 • assertTimeoutPreemptivelyはタイムアウト検知で検証処理を中断(interruput) • assertTimeoutPreemptivelyは検査対象処理は別スレッドで実行するため、ThreadLocalを利用しているコードは要注意 • 戻り値も例外も受け取れます! • より検証範囲を局所化できるよ • 良い子 • AssertTimeoutTest.java
  41. 3.4.Assertions(8) 無くなったAssertion assertThat!!

  42. 3.4.1.Third-party Assertion Libraries • assertThatが無いとか「xxxが無い」とか文句言わない • 使えるようにしといたから勝手にすればいいじゃ無い • HamcrestAssertionTest.java

  43. 3.5.Assumptions(1) • org.junit.jupiter.Assumptions (Maintained)にあるよ • JUnit 4.4から導入 • 思い入れはない •

    事前条件チェックの表明 • 事前条件違反をエラーにしない(skip扱い)
  44. 3.5.Assumptions(2) • JUnit4にもあるAssumptions • assumeFalse/assumeTrue • JUnit5で無くなったAssumptions • assumeNoException/assumeNotNull/assumeThat •

    新規に追加Assumptions • assumingThat • 第1引数がtrueの場合のみ第2引数のExecutableを評価 • AssumptionsTest.java
  45. 3.6. Disabling Tests • @Disabledを付けたテストクラスやメソッドはテストを行いません(skip扱い) • JUnit4の@Ignoreと同じ • DisabledClassTest.java •

    DisabledMethodTest.java
  46. 3.7. Tagging and Filtering • テストエンジンの実装によってフィルタリングするのに用いる • JUnit4の@Categoryと似たもの • フレームワーク上で何らかのマークしたい場合も使えば良いんじゃな

    い? • @Tagsってのもあるけど忘れていい(JavaDocにもそう書いてある) • TaggingTest.java
  47. 3.8. Nested Tests • テストメソッドを意味ある形でグルーピングする場合に内部クラス側に @Nestedと付ける • JUnit4のEnclosedに相当、RunWithで実現している方法と比較すると便利 • ネストは何段階でもOK!

    • ネストクラスは静的クラスじゃダメ。JUnit4とは違うので注意 • 静的じゃないからBeforeAllとAfterAllは使えないよ • TestingAStackTest.java
  48. 3.9. Dependency Injection for Constructors and Methods(1) • テストクラスのコンストラクタ、@Test、@TestFactory、@BeforeEach、 @AfterEach、@BeforeAll、@AfterAllが付与されたメソッドはパラメタを持

    つことができるよ • パラメタの解決は登録されたParameterResolver(Experimental)が行うよ(説 明はあとで) • Jupiterは3つのParameterResolverがBuild-inされてるいよ
  49. 3.9. Dependency Injection for Constructors and Methods(2) TestInfoParameterResolverとTestInfo • TestInfoParameterResolverはTestInfo(Experimental)型の引数にInjectionする

    ParameterResolverです • JUnit4のTestNameの代替として利用可能 • TestInfoは以下のプロパティを持つ • displayName:@DisplayNameのvalue。省略時はメソッド名 • tags:付与されたタグのSet • testClass:テストクラス • testMethod:テストメソッド • TestInfoTest.java
  50. 3.9. Dependency Injection for Constructors and Methods(3) RepetitionInfoParameterResolverとRepetitionInfo • RepetitionInfoParameterResolverはRepetitionInfo(Experimental)型の引数

    にInjectionするParameterResolverです • @RepeatedTest, @BeforeEach, @AfterEachが付いているメソッドに対して のみインジェクション可能 • 詳細はRepeated Tests(3.11)で
  51. 3.9. Dependency Injection for Constructors and Methods(4) TestReporterParameterResolverとTestReporter • TestReporterParameterResolverはTestReporter

    (Experimental)型の引数に InjectionするParameterResolverです • テストの動向を独自に記憶させてテストエンジン側で拾ったりできるらし い • テストエンジン側では、TestExecutionListener.reportingEntryPublished()を 介してアクセスできるらしい • テストエンジンに手をることに興味はないのでちゃんと調べてません • TestReporterTest.java
  52. 3.9. Dependency Injection for Constructors and Methods(5) 独自のParameterResolver • 独自にParameterResolverを必要とする場合

    • ParameterResolverを実装したクラスを作成する • 作成したクラスを@ExtendWithに記述 • 具体的には後(ExtensionModel) • MockitoExtension.java • MyMockitoTest.java
  53. 3.10. Test Interfaces and Default Methods • @Test,@TestFactory,@BeforeEach,@AfterEachをインタフェースのデフォルトメソッドで定 義できるよ •

    @BeforeAllや、@AfterAllもインタフェースのstaticメソッドで記述しておけば参照されるよ • @Tagや、@ExtendWithも引き継がれるよ • 再利用性とか考えるとこの形式で共通処理を作るよりはExtendWithによる拡張の方がい い気がする • TestLifecycleLogger.java/TestInterfaceDynamicTestsDemo.java/TimeExecutionLogger.java/TestInterf aceDemo.java • Testable.java/EqualsContract.java/ComparableContract.java/StringTests.java
  54. 3.11. Repeated Tests (1) • @ RepeatedTestアノテーションを付与したメソッドは指定回実行される • 例えば乱数が想定の範囲内であることとかリークの検出とか。。。に使うかなぁ •

    個々のテスト毎に@Testと同様の@BeforeEachや@AfterEachは呼び出されます • @RepeatedTestや@BeforeEach等が付いてるメソッドがRepetitionInfo型のパラメタを持つ場合は自動でインジェクショ ンされる • RepetitionInfoは以下のプロパティを持つ • currentRepetition:実行回数(1相対) • totalRepetitions:最大実行回数(1相対) • RepetitionInfoを@BeforeEachや@AfterEachでRepetitionInfoを受ける場合、同一テストクラスで@RepeatedTestと@Test の混在はできない • SimpleRepeartedTest.java
  55. 3.11. Repeated Tests (2) 表示名の変更 • @RepeatedTestにname属性を付けることで表示名を変更できます • {displayName}とつけるとTestInfoのdisplayNameに置き換わる •

    {currentRepetition}と付けると現在の実行回数に置き換わる • {totalRepetitions}と付けるとそう実行総数に置き換わる • 省略時は” repetition {currentRepetition} of {totalRepetitions}”という文字列が適用 される • RepeatedTestsDemoTest.java
  56. 3.12. Parameterized Tests(1) • @ParameterizedTest(Experimental)を付けることでテストデータとテストコードを分離することが できます • JUnit4でもランナーの切り替えである程度可能だったが不便 • junit-jupiter-paramsが別途必要

    • ParameterizedTestを書くには • 対象テストメソッドに@ParameterizedTestアノテーションをアノテートする • @XXXSourceを合わせてアノテートする • アノテートしないとそのテストはテストとして認識されない • 引数を受ける(引数受けなくても指定引数分テストは繰り返すだけでエラーにはならない) • Jupiterは6つのXXXSourceはbuild-inされてます
  57. 3.12. Parameterized Tests(2) @ValueSource, @EnumSource • @ValueSource(Experimental)は引数にString、int,long,doubleのいづれか1つの配列を指 定することで実現する • 複数の指定はできない

    • あんまり便利じゃないと思われ • @EnumSource(Experimental)は引数に指定したEnumをパラメタとして扱う • namesを指定するとその名前のEnumだけをパラメタとする • typoはエラーになります • あんまり便利じゃないと思われ • SimplePerameterizedTest.java
  58. 3.12. Parameterized Tests(3) @MethodSource • @MethodSource(Experimental)はnamesに指定したメソッドからの返却値をパラメタとして用いる • 複数パラメタの埋め込みもOK • nameじゃなくてnamesなのは複数メソッドを指定してもいいから

    • 指定するメソッドは、staticメソッドで引数なし • 戻り値はStream,Iterable,Iterator,または配列 • ParallelStream渡してもテストは並列には流れない orz • 複数引数をパラメタ化する場合はArguments(Experimental)を返すメソッドを用意する • Argumentsオブジェクトを生成するにはObjectArrayArguments(Experimental)を用いると良いらしい • MethodSourceParameterizedTest.java
  59. 3.12. Parameterized Tests(4) @CsvSource/CsvFileSource • @CSVSource(Experimental)はvalueの値をCSVの1行と捉えてパラメタに渡す • delimiterをデータに加える場合はシングルクォートで囲む • delimiterは変更可能

    • 改行をデータに加える場合もシングルクォートで囲む • @CsvFileSource(Experimental)はCSVファイルとしてデータを読み込む • resourcesにファイル名をクラスパスで指定、複数形なので複数して可能 • テストクラスからの相対パスで記述可能 • encoding(UTF-8),delimiter, lineSeparator(¥n)は変更可能 • パラメタは許容できるものは暗黙型変換が走る • カラム数<引数の場合はエラー、カラム数>引数の場合は無視 • カラム省略時はnull、Primitive型へは変換できないのでエラーとなる • 空文字のテストはできないかな? • CsvSourceParameterizedTest.java
  60. 3.12. Parameterized Tests(5) @ArgumentsSource • 上記以外の方法でパラメタを提供したい場合は@ArgumentsSource(Experimental)を利用 • 引数には、ArgumentsProvider(Experimental)を実装したクラスを指定する • ArgumentsProviderにあるargumentsメソッドの引数ContainerExtensionContextの説明は後で(やらないかも。。。)

    • パラメタは許容できるものは暗黙型変換が走る(後で) • UserGuideの例はArgumentsProviderの実装とデータが分離してないので再利用しにくいです • 汎用性を高めるためには… • ArgumentsSourceをアノテートしたアノテーションを定義する • 定義したアノテーションにパラメタを用意しデータを任意に取り込めるようにする • ArgumentsProviderと共にAnnotationConsumer(Experimental)を実装したクラスを用意する • acceptメソッドでアノテートされた情報を引き寄せる • 引き寄せた情報からパラメタを生成する • ArgumentsSourceParameterizedTest.java • MoreGenericPerameterizedTest.java
  61. 3.12. Parameterized Tests(6) 暗黙型変換 • User Guideはごちゃごちゃ書いててわかりにくいので • valueOf(String)メソッドを呼び出して変換してるもの •

    boolean/Boolean/byte/Byte/int/Integer/long/Long/float/Float/double/Double/Enum • parse(String)メソッドを呼び出して変換してるもの • Instant/LocalDate/LocalDateTime/LocalTime/OffsetDateTime/OffsetTime/Year/YearM onth/ZonedDateTime • ImplicitConversionTest.java
  62. 3.12. Parameterized Tests(7) 明示的型変換 • 引数毎に@ConvertWith(Experimental) を付与して個別に好き勝手な変換ができるよ • 引数にはArgumentConverter(Experimental)を実装したクラスを指定する •

    SimpleArgumentConverter(Experimental)を利用すると若干楽に実装できるかな • 引数毎にってところが使い勝手悪いよねぇとは個人的には思う • 別アノテーション作成すれば多少緩和されますが。。。 • JupiterにはJavaTimeArgumentConverterという明示的型変換をおこなているクラスがある ので参考にしたらいいよ • 利用するときは@ JavaTimeConversionPattern(Experimental)経由で • ExplicitConversionTest.java
  63. 3.12. Parameterized Tests(8) 表示名の拡張 • @ParameterizedTestのname属性で出力内容を変更できます • {index}:テスト実行回数(1相対) • {arguments}:全テストパラメータ

    • {0},{1}…:指定された引数 • やっぱり、結果XMLには反映されない。。。 • CustomizingDisplayNamesTest.java
  64. 3.12. Parameterized Tests(9) 3.12.5. Lifecycle and Interoperability • ParameterizedTestの個々のテストは@Testと同様のライフサイクルだよ •

    @BeforeEach、@AfterEachは個々のテスト前後で呼び出される • ParameterizedTestもTestと同様ParameterResolverで解決されたパラメタを 渡せますが、パラメタは最後の付与ししないとダメ • LifecycleAndInteroperabilityTest.java
  65. 3.13. Dynamic Tests • テストを動的に作れるよ • テストを作るメソッドは、@TestFactoryをアノテートしたメソッドで供給するよ • @TestFactoryは、DynamicTest(Experimental)のCollection,Iterable,Iterater、配列を返却しない といけないよ

    • DyamicTest以外を返すとランナーはエラーを検知するがXML結果ファイルにはエラーが記録されない? • DynamicTestは通常のテストケースと違い個々のテスト毎には@BerefoEach等のコールバック は行われません • @TestFactory毎にコールバックされる • DynamicTestはファクトリメソッド(DynamicTest.dynamicTest/stream)経由で作って欲しいとの事 • DynamicTestsDemoTest.java
  66. 5. Extension Model 5.1 Overview • JUnit4の時のRunWithによるランナー拡張/@Rule/@ClassRuleのような機 能はJUnit5ではExtention APIに統一されたよ •

    Extention(Experimental)自体はただのマーカーインタフェースなので機 能拡張したい場合は目的に応じたインタフェースを適時実装してね
  67. 5.2. Registering Extensions • Extensionを登録するには以下の2つの方法があるよ • @ExtendWithによる宣言的登録 • JavaのServiceLoaderを利用した自動的登録

  68. 5.2.1. Declarative Extension Registration • @ExtendWtihはクラス、インタフェース、メソッド、アノテーションに付与で きる • Extensionは1つ@ExtendWithに複数書くこともできるし、複数の @ExtendWithを定義してもいいよ

    • ExtendWithTest.java
  69. 5.2.2. Automatic Extension Registration • @ExtendWithっていちいち書かなくてもJavaのServiceLoader機構使えば 自動でExtensionの登録ができます 1. META-INF/services/org.junit.jupiter.api.extension.Extensionと言うファイルを作っ てその中に自動登録したいExtensionを実装しているクラスのFQCNを記述する

    2. システムプロパティ「junit.extensions.autodetection.enabled」にtrueをセットする • AutomaticExtensionRegistrationTest.java
  70. 5.2.3.Extension Inheritance • 親クラスやインタフェースに記述したExtensionは継承される • クラスに記述したExtensionは各テストメソッドにも適用される • 同一Extensionを複数適用することはできない • エラーにはならず無視される

    • ExtensionInheritanceTest.java
  71. 5.3. Conditional Test Execution(1) • ある条件が満たすor満たさない場合にテストの実行を取りやめるExtension • ContainerExecutionCondition:テストクラス全体を取り止めたい場合に作成 • TestExecutionCondition:テストメソッドの実行を取りやめたい場合に作成

    • ともにExperimental • それぞれevaluatedと言うAPIを持つ(引数が違う) • 戻り値は • テストをスキップしたい場合はConditionEvaluationResult#disable(String)の戻り値 • テストを実行していい場合はConditionEvaluationResult#enable(String)の戻り値 • のいずれかを返却。ConditionEvaluationResultはExperimental • @Disableでスキップできるのはこの拡張機能の実装であるDisabledConditionがbuild-inされてるから • 複数のConditionが適用されている場合1つでもスキップと判断するConditionがあればそのテストはスキップされる • Assumption使うよりはいい気がする • ConditionCheckTest.java • CapriciousConditionTest.java
  72. 5.3. Conditional Test Execution(2) • システムプロパティ「junit.conditions.deactivate」に無効化するConditionのクラス 名を書くと、その対象となるConditionは無効となります • 「*」と書くと全てのConditionが無効になります •

    「org.junit.*」と書くとorg.junitパッケージとそのサブパッケージ内にある全てのCondition が無効になります • 「 *.MyCondition」と書くとMyConditionと言う名のConditionが全て無効になります • 「 *System*」と書くとクラス名の一部に「System」とあるConditionが全て無効になります • 「 org.example.MyCondition」と書くとorg.example.MyConditionと言う名のConditionだけが 無効になります • ワイルドカードを書かない場合は全てFQCNと認識します
  73. 5.4. Test Instance Post-processing • TestInstancePostProcessor(Experimental)を実装したクラスをExtensionとし て登録するとテストクラスが実体化された後にコールバックを受けることが できます • DI的な動きさせるようなExtensionで使う

    • SpringExtensionや3.9で紹介したMockitoExtension.javaなどこのインタフェースの実 装例です • https://github.com/spring-projects/spring-framework/blob/master/spring- test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java
  74. 5.5. Parameter Resolution • ParameterResolver(Experimental)を実装したクラスをExtensionとして登録すると @BeforeAll, @AfterAll, @BeforeEach, @AfterEach, @Test,

    @TestFactoryがアノテートさ れてるメソッドに定義されているパラメタを解決することができます • 書いてないけど@RepeatedTestと@ParameterizedTestにも行けるよ • 同一メソッド、同一タイプの引数に対して複数のParameterResolverがインジェクション可 能(supportsメソッドがtrue)と返す場合はエラー • パラメタが定義されてるのに適切なParameterResolverが見つからない場合はエラーとな る • ParameterResolverTest.java • StringResolver.java/StringResolver2.java
  75. 5.6. Test Lifecycle Callbacks • テストの各種ライフサイクルに対するコールバックを受け取りたい場合は以下のいづれかの インタフェースの実装したクラスをExtensionとして登録する • BeforeAllCallback •

    BeforeEachCallback • BeforeTestExecutionCallback • AfterTestExecutionCallback • AfterEachCallback • AfterAllCallback • 全てExperimental • サンプルは5.10で
  76. 5.7. Exception Handling • TestExecutionExceptionHandler(Experimental)を実装したクラスを Extensionとして登録するとテストメソッドで発生した例外をハンドリングす ることができます • テストメソッドの例外ハンドリングだけなので@BeforeEach等で発生した例外のハン ドリングはできません

    • TestFactoryが返したDynamicTestの例外もハンドリングできません • ExceptionHandlerTest.java • ExceptionHandler.java
  77. 5.8. Keeping State in Extensions • Extensionで状態を保持したいならStoreを使ってね • Store自体に@APIはついてないけどOuterクラスのExtensionContextがExperimentalなので多分Storeも Experimental扱い

    • Store自体のライフサイクルはUserGuideに書いてない • Store自体は呼び出すたびに実体は変わるっぽい • ContainerExtensionContext経由で取得したStoreは同一テストクラスでテストしてる間有効っぽい • TestExtensionContext経由で取得したStoreは同一テストメソッドのライフサイクル終演まで有効っぽい • ちょっと追いきれてないので自信がありません • StoreTest.java • StoreExtension.java
  78. 5.9. Supported Utilities in Extensions • org.junit.platform.commons.supportパッケージにExtensionを作成する上 で有用なユーティリティがあります • AnnotationSupport:アノテーションを操作用のAPIなど

    • Maintained • ReflectionSupport:クラスやメソッドの検索用のAPIなど • Maintained • HierarchyTraversalMode:アノテーションの走査モードを表す列挙型 • Maintained
  79. 5.10. Relative Execution Order of User Code and Extensions •

    CallBackOrderTest.java • AllCallbacker.java • @BeforeEachとかの有無は関係なく コールバックされる • @NestedはBeforeAllの定義はでき ないのになぜかコールバックされる ContainerExecutionCondition TestInstancePostProcessor TestExecutionCondition
  80. 6. Migrating from Junit 6.1.Running JUnit 4 Tests on the

    JUnit Platform • junit-vintage-engineを使えばJUnit4やJUnit3のテストは実行できるよ • LegacyTest.java
  81. 6.2.Migration Tips • 既存のJUnit4のコードをJupiterに移行する際の注意点 • いろいろ書いてますが、vintage-engineもあるし書き換えなくていいと思います • どーしても書き換えたい人は以下を読めばいいんじゃ無いかな? • http://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4-tips

  82. 6.3. Limited JUnit 4 Rule Support • junit-jupiter-migration-supportを利用すれば以下のRuleはJupiterでも利用 できます •

    Verifier(VerifierSupportを登録する) • ExternalResource(ExternalResourceSupportを登録する) • ExpectedException(ExpectedExceptionSupportを登録する) • 3つともExperimental • VerifyTest.java
  83. 7.Advanced Topics • 力尽きた興味が無いのでスキップ • ここってIDEのプラグイン作ったりする人用っぽいし

  84. User Guideに詳しく書いてないけど調査が必要なこと • 各種Context • ExtensionContext • TestExtensionContext • ContainerExtensionContext

    • ParameterContext • JUnit5で言うところのContainerってなに? • 「例えばテストクラス」という記述はあったけど。。。(5.3)
  85. で、結局ありなん? • テストを書くという行為に関してはかなり良い • assertAll、assertThrows、assertTimeout、 assertTimeoutPreemptively、ParameterizedTest、Nested等は すぐにでも使いたい! • テスティング環境を整えるという点でも@Ruleや@RunWithで整えるよりはやるやすく感じ る

    • 個人的にはもぅJUnit5で行こうかとも思ってます • でも現時点では仕事では利用できないと思ってます • レポーティングがひどい • これが改善しないと辛いんじゃ無いかなぁ • 後ほとんどのAPIがまだExperimentalなのも怖いなぁ。。。
  86. 残念なお知らせ… • https://github.com/junit-team/junit5/milestones/ • 明日M5が出るようです…orz