首页 > 解决方案 > Kotlin reflection change instance and all members that use the instance

问题描述

We are using reflection to enable our tests to be started in different environments.

A typical test would look like this:

class TestClass {
  val environment: Environment = generateEnvironment("jUnit")
  val path: String = environment.path

  //Do test stuff
}

We are using reflection like this:

class PostgresqlTest{
  val classList: List<KClass<*>> = listOf(TestClass::class)
  val postgresEnv = generateEnvironment("postgres")

  @TestFactory
  fun generateTests(): List<DynamicTest> = classList.flatMap { testClass ->
    val instance = testClass.createInstance()
    environmentProperty(testclass).setter.call(instance, postgresEnv)

    //<<generate the dynamic tests>>

  }

  fun environmentProperty(testClass: KClass<*>) = 
    testClass.memberProperties.find {
      it.returnType.classifier == Environment::class
  } as KMutableProperty<*>
}

Now we have the issue that path != environment.path in the PostgresqlTest

I know this can be solved in the TestClass with lazy or get() like this

class TestClass {
  val environment: Environment = generateEnvironment("jUnit")

  val path: String by lazy { environment.path }

  // OR

  val path: String get() = environment.path
}

However this seems like a potential pitfall for future developers, especially since the first code snippet will work in TestClass and only fail for the tests where the environment is overwritten.

What is the cleanest way to ensure that path == environment.path when overwritting the property?

标签: reflectionkotlin

解决方案


我最终在 gradle 中为每个环境创建了一个新的测试任务:

task postgresqlIntegrationTest(type: Test, group: "Verification", description: "Runs integration tests on postgresql.") {
    dependsOn compileTestKotlin
    mustRunAfter test

    environment "env", "postgresql"

    useJUnitPlatform {
        filter {
            includeTestsMatching "*IT"
        }
    }
}

我的测试类只是像这样加载环境:

class TestClass {
  val environment: Environment = generateEnvironment(System.getenv("env") ?: "junit")
  //Do test stuff
}

推荐阅读