What is proper workaround for @BeforeAll in Kotlin
Solution 1
As stated in the documentation of @BeforeAll
:
Denotes that the annotated method should be executed before all @Test methods in the current class; analogous to JUnit 4’s @BeforeClass. Such methods must be static and are inherited.
The above is true for both Kotlin and Java. Keep in mind that by default Junit will create a separate instance of a test class per test case. It makes sense that @BeforeAll
will only work with static methods since it's supposed to be invoked before any code of current test case. A static method has no access to instance members because it can be invoked without an instance.
As stated in Spring documentation:
The "standaloneSetup" on the other hand is a little closer to a unit test.
The example shows that you should just use instance members like so:
class StandaloneTest {
val smsController = ... // create instance of controller
val MockMvcBuilders.standaloneSetup(smcController).build()
}
The usefulness of @BeforeAll
is limited and should generally be avoided as it potentially encourages runtime dependencies between test cases.
Solution 2
JUnit 5 has @TestInstance(PER_CLASS)
annotation that can be used for this purpose. One of the features that it enables is non-static BeforeAll
and AfterAll
methods:
@TestInstance(PER_CLASS)
class BeforeAllTests {
lateinit var isInit = false
@BeforeAll
fun setup() {
isInit = true
}
@TestFactory
fun beforeAll() = listOf(
should("initialize isInit in BeforeAll") {
assertTrue(isInit)
}
)
}
fun should(name: String, test: () -> Unit) = DynamicTest.dynamicTest("should $name", test)
Solution 3
You have access to the variables inside the companion object:
companion object {
private lateinit var objectToBeInitialized: Test
@BeforeAll
@JvmStatic
fun setup() {
objectToBeInitialized = Test()
}
}
Solution 4
JUnit 5 supports test extensions, for example BeforeAllCallback
import org.junit.jupiter.api.extension.BeforeAllCallback
import org.junit.jupiter.api.extension.ExtensionContext
class BeforeAllTests : BeforeAllCallback {
override fun beforeAll(context: ExtensionContext?) {
System.out.println("Before all executed");
}
}
In your Kotlin test class
@ExtendWith(BeforeAllTests::class)
class MyAppCoreTest : MyAppTest() {
@Test
fun someTest() { }
}
Greg Konush
Updated on June 07, 2022Comments
-
Greg Konush almost 2 years
Currently the JUnit 5 API only allows
@BeforeAll
on a method that is static.So if I do something like this, it will not compile:
@BeforeAll fun setup() { MockitoAnnotations.initMocks(this) mvc = MockMvcBuilders.standaloneSetup(controller).build() }
In order to have a static method in Kotlin, I have to use
companion object
like this:companion object { @JvmStatic @BeforeAll fun setup() { MockitoAnnotations.initMocks(this) mvc = MockMvcBuilders.standaloneSetup(smsController).build() } }
This will compile, but I don't have access to variables from the parent class. So what would be the idiomatic way to invoke JUnit 5
@BeforeAll
with Kotlin? -
Sébastien Deleuze about 6 yearsIt is also possible to define
PER_CLASS
as the default via ajunit-platform.properties
file, see Spring Kotlin documentation for more details: docs.spring.io/spring/docs/current/spring-framework-reference/…. -
Ulises about 6 years@SébastienDeleuze nice tip!
-
divonas over 4 yearsAndroid Studio could not resolve PER_CLASS.
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
-
Shahab Rauf almost 3 yearsPerfect Answer.