KotlinとJUnit5とTestInstanceアノテーション
概要
JavaでJUnit5を使っているときに、KotlinだとBeforeAll
とAfterAll
はどうなるのだろうと試したメモです。
環境
- Kotlin 1.2.60
- JUnit 5.2.0(jupiter)
試したこと
インスタンスメソッドでいい?
インスタンスメソッドにBeforeAll
やAfterAll
アノテーションをつけると怒られます。
(IDEA使ってるとメソッド名がグレーアウトになるので、事前に実行されなさそうなこともわかります)
package com.example.panage.junit5 import org.junit.jupiter.api.* class TestInstancePerMethodSample { @BeforeAll fun execBeforeAllTest() { println("before all") } @BeforeEach fun execBeforeEachTest() { println("before each") } @Test fun hoge() { println("feature") } @AfterEach fun execAfterEachTest() { println("after each") } @AfterAll fun execAfterAllTest() { println("after all") } }
org.junit.platform.commons.JUnitException: @BeforeAll method 'public final void com.example.panage.junit5.TestInstanceSample.execBeforeAllTest()' must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS). at org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.assertStatic(LifecycleMethodUtils.java:59) at org.junit.jupiter.engine.descriptor.LifecycleMethodUtils.lambda$findMethodsAndAssertStatic$0(LifecycleMethodUtils.java:83) at java.util.ArrayList.forEach(ArrayList.java:1257) at java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1080)
staticメソッドにするか、TestInstanceアノテーション(後述)を使うように言われます。
companion objectだけでいい?
companion object
の中に入れてみます。
companion object { @BeforeAll fun execBeforeAllTest() { println("before all") } @AfterAll fun execAfterAllTest() { println("after all") } }
before each feature after each Process finished with exit code 0
テストは実行できますが、BeforeAll
とAfterAll
の2つは実行されません。
JvmStaticアノテーションをつけたら?
@JvmStatic
を追加してみます。
companion object { @BeforeAll @JvmStatic fun execBeforeAllTest() { println("before all") } @AfterAll @JvmStatic fun execAfterAllTest() { println("after all") } }
before all before each feature after each after all Process finished with exit code 0
ちゃんとBeforeAll
とAfterAll
のメソッドも実行されました。
TestInstanceアノテーションなら?
先程のエラーメッセージでTestInstance
アノテーションを使うように言われていたのでつけてみます。
クラスに@TestInstance(TestInstance.Lifecycle.PER_CLASS)
を足して、BeforeAll
とAfterAll
をcompanion object
の外に出します。
package com.example.panage.junit5 import org.junit.jupiter.api.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) class TestInstancePerClassSample { @BeforeAll fun execBeforeAllTest() { println("before all") } @AfterAll fun execAfterAllTest() { println("after all") } @BeforeEach fun execBeforeEachTest() { println("before each") } @Test fun testFeature() { println("feature") } @AfterEach fun execAfterEachTest() { println("after each") } }
before all before each feature after each after all Process finished with exit code 0
ちゃんと実行できました!
TestInstanceアノテーション?
テストクラスのライフサイクルを変更するためのアノテーションです(そのまんま)
PER_CLASS
とPER_METHOD
が用意されていて、何も設定していない状態だとPER_METHOD
になります。
PER_METHOD
は従来どおりの動作で、テストメソッド実行ごとにテストクラスのインスタンスが生成されます。
PER_CLASS
では各テストメソッドに、同じインスタンスが使われます。(@Nested
を併せて使うと少し話は変わってくるようです)
設定の変更はアノテーションの他に、MavenやSystemプロパティなどからデフォルトでどちらにするかを変えられます。
junit-platform.properties
というファイルに書いてクラスパスルートに置くのが個人的には良いかな?と思っています。
TestInstanceとKotlinの関係はAPIドキュメントにも
Simplified declaration of @BeforeAll and @AfterAll methods in test classes implemented with the Kotlin programming language.
とあります。
デフォルトの設定を変えるのか、クラスごとに設定するのかはチームごとの方針に依るとは思いますが、
KotlinでBeforeAll
とAfterAll
を使うときは、PER_CLASS
にしておくと楽になりそうです。