Skip to content

testfiles fails to be auto-registered in newer Kotest versions #160

@apankowski

Description

@apankowski

testfiles extension doesn't seem to be auto-registered in newer Kotest versions.

Background

My setup (I think) is quite simple:

build.gradle.kts:

dependencies {
    testImplementation("io.kotest:kotest-runner-junit5::5.6.2")
    testImplementation("de.joshuagleitze:kotest-files:2.0.0")
}

how I'm using it in an example test:

class Test : FreeSpec({

    "Some" - {
        "nested" - {
            "test" {
                val directory = testFiles.createDirectory()
            }
        }
    }
})

However, this failed for me on any subsequent build:

java.nio.file.FileAlreadyExistsException: /home/andrzej/work/xyz/build/test-outputs/test-176899501
	at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:94)
	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
	at java.base/sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:397)
	at java.base/java.nio.file.Files.createDirectory(Files.java:700)
	at de.joshuagleitze.testfiles.DefaultTestFiles.createDirectory(DefaultTestFiles.kt:31)

Note that the directory is created under root test-outputs and not under test scope like described in README.

The issue

I attempted to debug this and found that Kotest initializes @AutoScan extensions in io.kotest:kotest-framework-engine-jvm, io.kotest.engine.config.applyConfigFromAutoScan.kt:16. However, to my surprise the scanning code doesn't discover testfiles' de.joshuagleitze.testfiles.kotest.KotestTestFilesAdapter object which I believe to be the testfiles' extension for Kotest. Because of that it doesn't register it as a Kotest extension, making testfiles run with ROOT_SCOPE context.

I don't have any environment variables set, Java properties set or Kotest-project-wide configuration that would be related to Kotest configuration.

Suspected reason

I think the reason are annotations:

  • Kotest during extension scanning uses ClassGraph which uses classfile bytecode for understanding which classes are matches for a given query. It uses the following query:

    classgraph().scan().use { result ->
        result.getClassesWithAnnotation(AutoScan::class.java.name)
            ...
    }
    

    The AutoScan here is io.kotest.core.annotation.AutoScan

  • testfiles' KotestTestFilesAdapter is annotated with io.kotest.core.spec.AutoScan (note the different package), which in newer Kotest versions is a type alias: typealias AutoScan = io.kotest.core.annotation.AutoScan

    I think the scanner, due to the different annotation package, doesn't consider testfiles' KotestTestFilesAdapter as a match.

A different problem

I though: hey, doesn't matter. I can use Kotest's project-wide configuration to manually register testfiles as its extension.

This doesn't work however, as testfiles' KotestTestFilesAdapter is internal and therefore I cannot reference it from my code.

Possible solution

  1. Migrate to updated Kotest annotation.
  2. Possibly make KotestTestFilesAdapter public so users can have fine-grained control over registration if they want to.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions