Kotlin 中 @BeforeAll 的正确解决方法是什么
What is proper workaround for @BeforeAll in Kotlin
目前 JUnit 5 API 只允许 @BeforeAll
在静态方法上。
所以如果我这样做,它不会编译:
@BeforeAll
fun setup() {
MockitoAnnotations.initMocks(this)
mvc = MockMvcBuilders.standaloneSetup(controller).build()
}
为了在 Kotlin 中有一个静态方法,我必须像这样使用 companion object
:
companion object {
@JvmStatic
@BeforeAll
fun setup() {
MockitoAnnotations.initMocks(this)
mvc = MockMvcBuilders.standaloneSetup(smsController).build()
}
}
这将编译,但我无法访问父 class 的变量。那么用 Kotlin 调用 JUnit 5 @BeforeAll
的惯用方法是什么?
如 @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.
以上内容对于 Kotlin 和 Java 都是正确的。请记住,默认情况下 Junit 将为每个测试用例创建一个单独的测试实例 class。 @BeforeAll
只适用于静态方法是有道理的,因为它应该在当前测试用例的任何代码之前被调用。静态方法 无法访问实例成员,因为它可以在没有实例的情况下被调用 。
如 Spring 文档所述:
The "standaloneSetup" on the other hand is a little closer to a unit test.
该示例表明您应该像这样使用实例成员:
class StandaloneTest {
val smsController = ... // create instance of controller
val MockMvcBuilders.standaloneSetup(smcController).build()
}
@BeforeAll
的用处有限,通常应避免使用,因为它可能会鼓励测试用例之间的运行时依赖性。
JUnit 5 有 @TestInstance(PER_CLASS)
注释可用于此目的。它启用的功能之一是 non-static BeforeAll
和 AfterAll
方法:
@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)
JUnit 5 支持测试扩展,例如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");
}
}
在你的 Kotlin 测试中 class
@ExtendWith(BeforeAllTests::class)
class MyAppCoreTest : MyAppTest() {
@Test
fun someTest() { }
}
在 @SpringBootTest
中,这里有一个简单的解决方案。请注意,@BeforeAll
函数可以使用由 Spring.
注入的属性
@SpringBootTest(classes = [Application::class])
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTest {
@Autowired
lateinit var someBean: SomeBean
lateinit var propertyForAll: PropertyForAll
@BeforeAll
fun setup() {
propertyForAll = PropertyForAll(someBean.valueXyz())
}
@Test
fun `First test`() {
val something = propertyForAll.findSomething("Banana")
// test continues
}
@Test
fun `Second test`() {
val something = propertyForAll.findSomething("Orange")
// test continues
}
}
值得一看:
- 官方 Spring Boot with Kotlin tutorial
中的 测试实例生命周期 部分
- 这个DZone article有很好的回应和解释。
您可以访问 companion 对象中的变量:
companion object {
private lateinit var objectToBeInitialized: Test
@BeforeAll
@JvmStatic
fun setup() {
objectToBeInitialized = Test()
}
}
目前 JUnit 5 API 只允许 @BeforeAll
在静态方法上。
所以如果我这样做,它不会编译:
@BeforeAll
fun setup() {
MockitoAnnotations.initMocks(this)
mvc = MockMvcBuilders.standaloneSetup(controller).build()
}
为了在 Kotlin 中有一个静态方法,我必须像这样使用 companion object
:
companion object {
@JvmStatic
@BeforeAll
fun setup() {
MockitoAnnotations.initMocks(this)
mvc = MockMvcBuilders.standaloneSetup(smsController).build()
}
}
这将编译,但我无法访问父 class 的变量。那么用 Kotlin 调用 JUnit 5 @BeforeAll
的惯用方法是什么?
如 @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.
以上内容对于 Kotlin 和 Java 都是正确的。请记住,默认情况下 Junit 将为每个测试用例创建一个单独的测试实例 class。 @BeforeAll
只适用于静态方法是有道理的,因为它应该在当前测试用例的任何代码之前被调用。静态方法 无法访问实例成员,因为它可以在没有实例的情况下被调用 。
如 Spring 文档所述:
The "standaloneSetup" on the other hand is a little closer to a unit test.
该示例表明您应该像这样使用实例成员:
class StandaloneTest {
val smsController = ... // create instance of controller
val MockMvcBuilders.standaloneSetup(smcController).build()
}
@BeforeAll
的用处有限,通常应避免使用,因为它可能会鼓励测试用例之间的运行时依赖性。
JUnit 5 有 @TestInstance(PER_CLASS)
注释可用于此目的。它启用的功能之一是 non-static BeforeAll
和 AfterAll
方法:
@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)
JUnit 5 支持测试扩展,例如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");
}
}
在你的 Kotlin 测试中 class
@ExtendWith(BeforeAllTests::class)
class MyAppCoreTest : MyAppTest() {
@Test
fun someTest() { }
}
在 @SpringBootTest
中,这里有一个简单的解决方案。请注意,@BeforeAll
函数可以使用由 Spring.
@SpringBootTest(classes = [Application::class])
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTest {
@Autowired
lateinit var someBean: SomeBean
lateinit var propertyForAll: PropertyForAll
@BeforeAll
fun setup() {
propertyForAll = PropertyForAll(someBean.valueXyz())
}
@Test
fun `First test`() {
val something = propertyForAll.findSomething("Banana")
// test continues
}
@Test
fun `Second test`() {
val something = propertyForAll.findSomething("Orange")
// test continues
}
}
值得一看:
- 官方 Spring Boot with Kotlin tutorial 中的 测试实例生命周期 部分
- 这个DZone article有很好的回应和解释。
您可以访问 companion 对象中的变量:
companion object {
private lateinit var objectToBeInitialized: Test
@BeforeAll
@JvmStatic
fun setup() {
objectToBeInitialized = Test()
}
}