kotest / kotest-intellij-plugin

The official Kotest plugin for Intellij and Android Studio
Apache License 2.0
179 stars 25 forks source link

Running tests from a custom compilation uses wrong Gradle task for tests #266

Open kirillzh opened 1 year ago

kirillzh commented 1 year ago

I have a custom integrationTest compilation in KMP project and a JVM target. I’ve got some tests in jvmIntegrationTest source set. When trying to run these tests from IDE using Kotest plugin, it runs cleanJvmTest and jvmTest tasks, I would expect it to run cleanJvmIntegrationTest and jvmIntegrationTest tasks.

Is it something that Kotest plugin need to somehow pick up on, or are there additional steps I need to take when configuring my compilation?

Here's how I configure integrationTest compilation for my JVM target:

jvm {
  val integrationTest by compilations.creating {
    val main by compilations.getting
    associateWith(main)

    defaultSourceSet {
      dependencies {
        // Compile against the main compilation's compile classpath and outputs:
        implementation(main.compileDependencyFiles + main.output.classesDirs)
        implementation(kotlin("test-junit"))
      }
    }

    // Define a Gradle task to run the integration tests
    project.tasks.register<Test>("jvmIntegrationTest") {
      description = "Run JVM integration tests"
      group = VERIFICATION_GROUP
      classpath = compileDependencyFiles + runtimeDependencyFiles + output.allOutputs
      testClassesDirs = output.classesDirs
    }
  }
}
kirillzh commented 1 year ago

This is where plugin looks for JVM test tasks: https://github.com/kotest/kotest-intellij-plugin/blob/8b7fdab73e1f6611e36702b7bb90e7d60257bcc6/src/main/kotlin/io/kotest/plugin/intellij/toolwindow/treeModel.kt#L59

What would be the most sensible approach here to make it pick up test tasks from other compilations?

kirillzh commented 1 year ago

As a workaround, created this task that automatically generates a run configuration for each integration test file:

/**
 * Generate runner configuration for JVM Integration tests manually, until Kotest plugin
 * supports running tests from custom test compilations: https://github.com/kotest/kotest-intellij-plugin/issues/266.
 */
private fun Project.generateJvmIntegrationTestRunConfiguration() {
  val runConfigurationsDir = rootDir.resolve(".idea/runConfigurations")
  runConfigurationsDir.mkdirs()

  val integrationTestDir = projectDir.resolve("src/jvmIntegrationTest/kotlin")

  if (integrationTestDir.exists()) {
    // Generate run configuration for each integration test file, if any:
    val testFiles = integrationTestDir.walk().filter {
      it.isFile && it.name.endsWith("Tests.kt")
    }
    testFiles.forEach { file ->
      println("Generating run configuration for $file")
      val configName = file.nameWithoutExtension
      val fullyQualifiedName =
        file.toRelativeString(integrationTestDir).replace("/", ".").removeSuffix(".kt")

      val runConfigurationXml = """
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="$configName" type="GradleRunConfiguration" factoryName="Gradle">
    <ExternalSystemSettings>
      <option name="executionName" />
      <option name="externalProjectPath" value="${"$"}PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list>
          <option value="${project.path}:jvmIntegrationTest" />
          <option value="--tests" />
          <option value="&quot;$fullyQualifiedName&quot;" />
        </list>
      </option>
      <option name="vmOptions" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <ForceTestExec>true</ForceTestExec>
    <method v="2" />
  </configuration>
</component>
""".trimIndent()

      val runConfigurationFile = runConfigurationsDir.resolve("$configName.xml")
      println("Generating into $runConfigurationFile")
      runConfigurationFile.writeText(runConfigurationXml)
    }
  }
}
sksamuel commented 1 year ago

This is where plugin looks for JVM test tasks:

https://github.com/kotest/kotest-intellij-plugin/blob/8b7fdab73e1f6611e36702b7bb90e7d60257bcc6/src/main/kotlin/io/kotest/plugin/intellij/toolwindow/treeModel.kt#L59

What would be the most sensible approach here to make it pick up test tasks from other compilations?

We need a way to determine if a module is a test module or not, programatically, rather than using the string names.