Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can I use prepareSpec without @AutoScan? #3979

Open
dondod opened this issue Apr 23, 2024 · 7 comments
Open

Can I use prepareSpec without @AutoScan? #3979

dondod opened this issue Apr 23, 2024 · 7 comments

Comments

@dondod
Copy link

dondod commented Apr 23, 2024

I currently use an approach like the following to set up a database schema before tests run. It needs to happen before any test class is loaded.

class KotestExtensions {
    @AutoScan
    class PrepareSpecTestListener : TestListener {
        override suspend fun prepareSpec(kclass: KClass<out Spec>) {
            // set up database, etc.
        }
    }
}

But this generates this warning:

Warning: Kotest autoscan is enabled. This means Kotest will scan the classpath for extensions that are annotated with @AutoScan.
 To avoid this startup cost, set autoscan to false by setting the system property 'kotest.framework.classpath.scanning.config.disable=true'. In 6.0 this value will default to true. For further details see 
https://kotest.io/docs/next/framework/project-config.html#runtime-detection

I've tried disabling autoscan in another project that doesn't need the database setup, and it speeds up the test startup by several seconds (maybe 5 or more).

Is there a way to use prepareSpec without using @AutoScan?

@Kantis
Copy link
Member

Kantis commented Apr 23, 2024

You can define kotest.properties (details here) with the following content:

kotest.framework.classpath.scanning.config.disable=true
kotest.framework.classpath.scanning.autoscan.disable=true
kotest.framework.config.fqn=com.myproject.KotestConfig

Where com.myproject.KotestConfig is

object KotestConfig : AbstractProjectConfig() {
  override fun extensions() = listOf(
    PrepareSpecTestListener()
  )
}

That should get rid of runtime detection while also letting you configure Kotest.

@dondod
Copy link
Author

dondod commented Apr 23, 2024

Thanks! That almost worked.. I get an error though:

io.kotest.engine.spec.SpecInstantiationException: Could not create instance of class com.myproject.MySpec. Specs must have a public zero-arg constructor.
	at io.kotest.engine.spec.InstantiateSpecKt.javaReflectNewInstance(instantiateSpec.kt:46)
	at io.kotest.engine.spec.InstantiateSpecKt.createAndInitializeSpec(instantiateSpec.kt:30)
	at io.kotest.engine.spec.InstantiateSpecKt.instantiate(instantiateSpec.kt:11)
	at io.kotest.engine.spec.SpecRefKt.instance(SpecRef.kt:14)
	at io.kotest.engine.spec.SpecExecutor.createInstance-gIAlu-s(SpecExecutor.kt:63)
	at io.kotest.engine.spec.SpecExecutor.access$createInstance-gIAlu-s(SpecExecutor.kt:24)
	at io.kotest.engine.spec.SpecExecutor$execute$innerExecute$1.invokeSuspend(SpecExecutor.kt:40)
...

Would that be because I pass a mock into the spec constructor? e.g.,

class MySpec(@MockkBean private val foo: Foo) : DescribeSpec({
    //
})

@dondod
Copy link
Author

dondod commented Apr 26, 2024

Moving the parameters out of the MySpec constructor works, but then I need to use init {... and change the way all the passed-in (usually auto-wired) arguments are dealt with. This is a common pattern with Spring Boot (for better or worse), so I wonder if there's a way allow passing arguments to the spec constructors.

@Kantis
Copy link
Member

Kantis commented May 8, 2024

@dondod sorry for taking so long.. It's because the SpringAutowireConstructorExtensions from kotest-extensions-spring relies on @AutoScan to be discovered. When you disable scanning, you need to also register this extension manually from your KotestConfig.

You probably also want to register the SpringExtension

@dondod
Copy link
Author

dondod commented May 8, 2024

Thanks @Kantis! This works well in many cases for me (reducing test startup time by 7-8 seconds), but now the mocks declared by @MockkBean only work once. I'll see if I can narrow down the cause.

@Kantis
Copy link
Member

Kantis commented May 9, 2024

Feel free to post a small example repo 🙂

@dondod
Copy link
Author

dondod commented May 9, 2024

Thanks, I'll try that soon..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants