Kotlin中@BeforeAll的适当解决方法是什么?

43

目前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()
    }
}

这段代码可以编译通过,但无法访问父类的变量。那么,在 Kotlin 中调用 JUnit 5 的 @BeforeAll 应该如何做到最符合惯例?


我认为你使用 @BeforeAll 是有问题的。为什么不使用 @BeforeEach 呢? - Stefan Birkner
3
我曾认为 JUnit 5 只实例化测试类一次,但看起来它对每个测试用例都这样做。这使得 @BeforeAll@BeforeEach 之间几乎没有区别... 几乎没有区别。 - Greg Konush
5个回答

45

JUnit 5有一个@TestInstance(PER_CLASS)注释,可以用于此目的。它启用的功能之一是非静态的BeforeAllAfterAll方法:

@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)

1
还可以通过 junit-platform.properties 文件将 PER_CLASS 定义为默认值,有关详细信息,请参阅 Spring Kotlin 文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/languages.html#testing。 - Sébastien Deleuze
5
Android Studio 无法解析 PER_CLASS。@TestInstance(TestInstance.Lifecycle.PER_CLASS) - divonas

15

您可以访问伴生对象(companion)中的变量:

    companion object {

        private lateinit var objectToBeInitialized: Test

        @BeforeAll
        @JvmStatic
        fun setup() {
            objectToBeInitialized = Test()
        }
    }

1
完美答案。 - Shahab Rauf

9
@BeforeAll文档中所述:

表示使用注释的方法应在当前类中的所有@Test方法之前执行; 类似于JUnit 4的@BeforeClass。这些方法必须是静态的并且被继承。

对于Kotlin和Java都是如此。请记住,Junit默认情况下会为每个测试用例创建一个单独的测试类实例。@BeforeAll只能与静态方法一起使用,因为它应在当前测试用例的任何代码之前调用。 静态方法无法访问实例成员,因为可以在没有实例的情况下调用该方法

如Spring文档中所述:

另一方面,“standaloneSetup”更接近于单元测试。

示例说明应仅使用实例成员,如下所示:

class StandaloneTest {
  val smsController = ... // create instance of controller
  val MockMvcBuilders.standaloneSetup(smcController).build()
}

@BeforeAll 的实用性有限,通常应避免使用,因为它可能会鼓励测试用例之间的运行时依赖关系。


4

JUnit 5支持测试扩展,例如BeforeAllCallback

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 测试类中:
@ExtendWith(BeforeAllTests::class)
class MyAppCoreTest : MyAppTest() {

    @Test
    fun someTest() { }
}

-1
在一个 @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
    }
}

值得一看:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接