I'm new to Kotlin and have a simple list application I'm working on.
- Spring Boot 3.2.1
- kotest 5.8.0
- kotest spring extension 1.1.3
Dependencies:
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("jakarta.validation:jakarta.validation-api")
implementation("org.flywaydb:flyway-core")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:$springDocOpenApiStarterWebmvcUiVersion")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
// implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-web")
runtimeOnly("com.h2database:h2")
runtimeOnly("org.postgresql:postgresql")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
testImplementation("com.ninja-squad:springmockk:$springmockkVersion")
testImplementation("io.kotest:kotest-assertions-core:$kotestVersion")
testImplementation("io.kotest:kotest-assertions-json:$kotestVersion")
testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion")
testImplementation("io.kotest.extensions:kotest-extensions-spring:$kotestExtensionsSpringVersion")
// testImplementation("org.springframework.security:spring-security-test")
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(group = "org.assertj", module = "assertj-core")
exclude(group = "org.hamcrest", module = "hamcrest")
exclude(group = "org.mockito", module = "mockito-core")
exclude(group = "org.mockito", module = "mockito-junit-jupiter")
}
I'm writing some basic unit tests using kotest and the kotest spring extension.
However I have an error when trying to have a spring jpa (or crudrepository) bean created in the test context.
This only happens so far with spring repository interface. Not with a simple @Component annotated class. I can't figure out what I'm doing wrong.
Repository:
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository interface LrmListRepository : JpaRepository<LrmList, Long>
Test Class:
import io.kotest.core.spec.style.WordSpec
import io.kotest.extensions.spring.SpringExtension
import net.flyingfishflash.loremlist.domain.lrmlist.data.LrmListRepository
import net.flyingfishflash.loremlist.domain.lrmlist.exceptions.ListNotFoundException
import org.junit.jupiter.api.assertThrows
import org.springframework.test.context.ContextConfiguration
@ContextConfiguration(classes = [LrmListRepository::class])
class LrmListControllerTests(repository: LrmListRepository) : WordSpec() {
override fun extensions() = listOf(SpringExtension)
init {
"SpringExtension" should {
"have autowired the repository" {
assertThrows<ListNotFoundException> {
repository.findById(1L)
}
}
}
}
}
The test class is based on the example here: https://kotest.io/docs/extensions/spring.html
This test fails to build with this error:
Caused by: org.springframework.test.context.aot.TestContextAotException: Failed to process test class [net.flyingfishflash.loremlist.domain.lrmlist.LrmListControllerTests] for AOT
Caused by: java.lang.IllegalStateException: No constructor or factory method candidate found for Root bean: class [net.flyingfishflash.loremlist.domain.lrmlist.data.LrmListRepository]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null and argument types []
Any insight would be much appreciated thank you!
Resolution
I did finally get the controller tests working the way I wanted, using a combination of spring annotations/kotest/mockk.
Hopefully this example helps someone also sifting through the testing landscape in kotlin.
Controller Test Class: