kotest更改环境变量

Vic*_*lyk 5 testing kotlin kotest

我正在使用 Kotests 为 Ktor 应用程序编写测试,但偶然发现了如何在全局范围内更改测试的环境变量的问题。我尝试过添加withEnvironment,但它给我带来了非常奇怪的错误

Unable to make field private final java.util.Map java.util.Collections$UnmodifiableMap.m accessible: module java.base does not "opens java.util" to unnamed module @3daa422a
java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.Map java.util.Collections$UnmodifiableMap.m accessible: module java.base does not "opens java.util" to unnamed module @3daa422a
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
Run Code Online (Sandbox Code Playgroud)

我的测试文件看起来像这样

class VisitorSpec : FreeSpec({
    val ds = createDataSourceTest()

    val visitor = RegisterVisitorDTO(
        email = TestConstants.VISITOR_EMAIL,
        username = TestConstants.VISITOR_USERNAME,
        password = TestConstants.PASSWORD,
        firstName = TestConstants.VISITOR_FIRST_NAME,
        lastName = TestConstants.VISITOR_LAST_NAME,
        gender = TestConstants.VISITOR_GENDER,
        birthday = TestConstants.VISITOR_BIRTHDAY,
    )


    "check visitor routes" - {

        val loginData = LoginDTO(TestConstants.VISITOR_EMAIL + 0, TestConstants.PASSWORD)

        "can get list of visitors with correct query" {
            withEnvironment(
                mapOf(
                    "POSTGRES_URL" to "jdbc:postgresql://localhost:5432/test",
                    "POSTGRES_USERNAME" to "test_user",
                    "POSTGRES_PASSWORD" to "test_pass"
                )
            ) {
                testApplication {
                    val client = getClient(ds)
                    repeat(6) {
                        registerConfirmedUser(
                            client, visitor.copy(
                                email = "${TestConstants.VISITOR_EMAIL}$it",
                                username = "${TestConstants.VISITOR_USERNAME}$it",
                            )
                        )
                    }

                    val accessToken = loginUser(client, loginData).run { this.body<LoginResponseDTO>().accessToken }
                    client.get("/api/v1/visitors?page=1&count=5") {
                        header("Authorization", "Bearer $accessToken")
                    }.apply {
                        val response = this.body<VisitorPaginatedResponseDTO>()
                        response.data.size.shouldBe(5)
                        response.totalCount.shouldBe(6)
                        response.currentPage.shouldBe(1)
                    }
                }
            }
        }
...
Run Code Online (Sandbox Code Playgroud)

如果我删除

 withEnvironment(
                mapOf(
                    "POSTGRES_URL" to "jdbc:postgresql://localhost:5432/test",
                    "POSTGRES_USERNAME" to "test_user",
                    "POSTGRES_PASSWORD" to "test_pass"
                )
            )
Run Code Online (Sandbox Code Playgroud)

它会正常工作,但使用默认数据库,对此有什么建议吗?

在某些地方,建议使用

   override fun listeners() = listOf(
            SystemEnvironmentTestListener("fooKeyEnv", "barValueEnv"),
            SystemPropertyTestListener("fooKeyProp", "barValueProp")
        )
Run Code Online (Sandbox Code Playgroud)

但 ide 告诉我这个方法已被弃用。预先感谢您的任何建议。

hot*_*key 4

最新的 Java 版本禁止使用默认访问设置修改环境变量(JEP 403:强封装 JDK 内部)。Kotest和其他一些操作环境变量的测试框架受此影响,您可以找到相关问题:

一种解决方案是将参数添加到运行测试的 JVM,这将使 Java 平台模块系统允许访问测试框架使用的 API。这是解释这些论点的答案: How to set environment variable in Java without 'illegal reflecting access'? 如何使用附加打开?

如果您没有在代码中使用 Java 模块,则该参数的最简单形式是:

--add-opens java.base/java.util=ALL-UNNAMED
Run Code Online (Sandbox Code Playgroud)

如果您使用 Gradle 运行测试,那么您可以将此参数传递给jvmArgs任务的test

--add-opens java.base/java.util=ALL-UNNAMED
Run Code Online (Sandbox Code Playgroud)

注意:即使某些代码需要非法访问 JDK 内部,以这种方式修改模块访问也可以使测试通过。确保您的代码不会执行此操作,或者您有其他测试来检查此情况而不修改模块访问权限。


似乎其他一些库(例如 )system-stubs提供了一种在测试中修改环境变量的方法,而无需对 JDK 内部进行非法反射访问。