使用环境变量时如何在 ktor 中进行测试?

Posted

技术标签:

【中文标题】使用环境变量时如何在 ktor 中进行测试?【英文标题】:How to test in ktor while using environment variables? 【发布时间】:2021-06-12 09:48:25 【问题描述】:

我在我的 Ktor 项目中使用 PostgreSQL 数据库。我在 Intellij Idea 的系统环境变量中保存了 JDBC_URL、JDBC_DRIVER...。

    fun hikari(): HikariDataSource
    val config = HikariConfig()
    ****config.driverClassName =  System.getenv("JDBC_DRIVER")***********
    ****config.jdbcUrl = System.getenv("JDBC_DATABASE_URL")*************
    config.maximumPoolSize = 3
    config.isAutoCommit = false
    config.transactionIsolation = "TRANSACTION_REPEATABLE_READ"
    val password = System.getenv("DB_PASSWORD")
    if(password != null)
        config.password = password
    
    config.validate()

    return HikariDataSource(config)

一切正常。但是在自动化测试时,它会在访问这些环境变量时给出 NULL POINTER EXCEPTION

测试功能:

    @Test
fun testUserLogin_wrongPassword_false()
    withTestApplication(
        module(testing = true)
    ) 
        handleRequest(HttpMethod.Post,"/v1/users/login")
            addHeader("Content-Type","application/json")
            setBody(""""email": "temp","password": "temp"""")
        .apply 
            assertEquals(HttpStatusCode.BadRequest,response.status())
        
    

例外:

java.lang.NullPointerException
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at com.zaxxer.hikari.HikariConfig.attemptFromContextLoader(HikariConfig.java:899)
at com.zaxxer.hikari.HikariConfig.setDriverClassName(HikariConfig.java:474)
at com.example.repository.DatabaseFactory.hikari(DatabaseFactory.kt:40)
at com.example.repository.DatabaseFactory.init(DatabaseFactory.kt:21)
at com.example.ApplicationKt.module(Application.kt:41)
at com.example.ApplicationTest$testUserLogin_wrongPassword_false$1.invoke(ApplicationTest.kt:31)
at com.example.ApplicationTest$testUserLogin_wrongPassword_false$1.invoke(ApplicationTest.kt:17)
at io.ktor.server.testing.TestEngineKt$withTestApplication$1.invoke(TestEngine.kt:67)
at io.ktor.server.testing.TestEngineKt$withTestApplication$1.invoke(TestEngine.kt)
at io.ktor.server.testing.TestEngineKt.withApplication(TestEngine.kt:49)
at io.ktor.server.testing.TestEngineKt.withApplication$default(TestEngine.kt:43)
at io.ktor.server.testing.TestEngineKt.withTestApplication(TestEngine.kt:66)
at com.example.ApplicationTest.testUserLogin_wrongPassword_false(ApplicationTest.kt:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:119)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.lang.Thread.run(Thread.java:745)

我们如何在测试时访问环境变量,或者在使用数据库时还有其他方法可以测试吗?

【问题讨论】:

【参考方案1】:

您可以引入额外的抽象级别来访问环境变量(通过为hikari 函数创建一个参数,然后在测试中传递它的参数)或在每次测试之前全局改变所需的环境变量(@987654321 @)。此外,您可以对整个 HikariDataSource 使用模拟。

【讨论】:

您好,先生,感谢您的回复。你能解释一下什么是嘲笑 这里可以找到解释devopedia.org/…。【参考方案2】:

在测试中,您可以使用 MapApplicationConfig.put 方法,而不是使用 application.conf 来定义配置属性:

withTestApplication(
(environment.config as MapApplicationConfig).apply 
    // Set here the properties
    put("youkube.session.cookie.key", "03e156f6058a13813816065")
    put("youkube.upload.dir", tempPath.absolutePath)

main() // Call here your application's module
)

https://ktor.io/docs/testing.html#defining-configuration-properties-in-tests

【讨论】:

首先感谢您的回复?。我见过那种方法,但它是用于配置属性的,但我要求的是环境变量。如何在其中传递环境变量。

以上是关于使用环境变量时如何在 ktor 中进行测试?的主要内容,如果未能解决你的问题,请参考以下文章

练习使用Eclipse进行单元测试

在Postman中如何设置环境变量?

jdk+Tomcat环境搭建

postman使用--环境变量

配置java环境变量时求解下面为啥Path编辑命令是灰色的,配置环境变量的时候要用那个吧?

运行 Inno Setup Installer 时如何修改 PATH 环境变量?