Skip to content

@MockitoBean is not properly initialized in Kotlin test class with Spring Boot 3.4.4 #34832

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

Open
JayAndromeda opened this issue Apr 25, 2025 · 6 comments
Labels
in: test Issues in the test module status: waiting-for-feedback We need additional information before we can continue status: waiting-for-triage An issue we've not yet triaged or decided on

Comments

@JayAndromeda
Copy link

JayAndromeda commented Apr 25, 2025

I am running into an issue when upgrading from Spring Boot 3.3.9 to 3.4.4 where my tests with Mocked beans fail to run due to an initialization error on our lateinit fields. My Mockito versions are managed by the spring-boot-starter-test artifact which would be 5.11.0 -> 5.14.2.

My exact Mockito error is:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced or misused argument matcher detected here: <package path>FooTest.anyTokenPayLoad.kt 

I think this is caused by a Kotlin exception:

kotlin.UninitializedPropertyAccessException: lateinit property tokenType has not been initialized

I looked at this issue #34516 which is strikingly similar to our issue but of course we do not use spy beans.

These tests work as intended on Spring Boot 3.3.9 and Mockito 5.11.0. They do not work on Spring Boot 3.4.4 and do not work on either Mockito version which leads me to believe it is a possible issue with how spring is initializing these lateinit fields via @Autowired.

Thank you for taking a look into and I apologize if it was answered somewhere but I tried to look in the issues list.

Other info:

  • 'kotlin_version', "1.7"
  • 'org.jetbrains.kotlin.plugin.spring' version '2.1.20'
  • 'org.jetbrains.kotlin.jvm' version '2.1.20'

I attached stubbed versions of our test class, service class that allows the autowire, and object that holds the lateinit field in question.

import org.mockito.Mockito.`when`
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.test.context.SpringBootTest
import org.junit.jupiter.api.Test

@ExtendWith(SpringExtension::class)
@EnableConfigurationProperties(value = [TokenConfiguration::class])
@ContextConfiguration(classes = [TokenService::class])
@SpringBootTest    
open class FooTest {
    
    @Autowired
    private lateinit var subject : TokenService

    @Autowired
    private lateinit var tokenConfiguration : TokenConfiguration

    @MockitoBean
    private lateinit var tokenGenerator : TokenGenerator
    
    @Test
    fun `generateToken with valid generate token request returns access token`() {
        val generateTokenRequest = GenerateTokenRequest(foo, bar)
        `when`(tokenGenerator.generateAccessToken(anyTokenPayLoad(generateTokenRequest))).thenReturn(accessToken)
        /* 
        We also tried a stub such as the following line but it gave us the same error

        `when`(tokenGenerator.generateAccessToken(any(TokenPayLoad::class.java))).thenReturn(accessToken) */
        val response = subject.generateToken(generateTokenRequest)
        assertThat(response).isNotNull
        assertThat(response.ttl).isEqualTo(ttl)
        assertThat(response.tokenType).isEqualTo(tokenType)
    }

    @Suppress("UNCHECKED_CAST")
    private fun <TokenPayLoad> anyTokenPayLoad(generateTokenRequest: GenerateTokenRequest): TokenPayLoad {
        return any() ?: TokenPayLoad(generateTokenRequest, tokenConfiguration) as TokenPayLoad
    }
}
import org.springframework.beans.factory.annotation.Value

@ConfigurationProperties
@RefreshScope
open class TokenConfiguration {

    @Value("Bearer")
    lateinit var tokenType: String

    @Value("3600L")
    var defaultTTL: Long = 0L
}

@Service
@EnableConfigurationProperties(value = [TokenConfiguration::class])
class TokenService
@Autowired
constructor(private var tokenGenerator: TokenGenerator,
            private var tokenConfiguration: TokenConfiguration) {
    fn generateToken(): GenerateTokenResponse{
        //some logic
        return generateTokenResponse 
    }             
} 
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Apr 25, 2025
@dmitrysulman
Copy link
Contributor

Please provide a complete sample that reproduces the problem. The attached code can't be run as-is due to some missing classes (e.g., TokenGenerator).

@snicoll snicoll transferred this issue from spring-projects/spring-boot Apr 26, 2025
@JayAndromeda
Copy link
Author

JayAndromeda commented Apr 28, 2025

this is the stubbed TokenGenerator class, but it should be noted that the issue really isn't with this class at all.

@Service
@EnableConfigurationProperties(value = [TokenConfiguration::class])
class TokenGenerator  @Autowired constructor(private val tokenConfiguration: TokenConfiguration) {
    fun generateAccessToken(tokenPayLoad: TokenPayLoad): String {
        lateinit var token : String
        val jwtClaims = buildClaims(tokenConfiguration.issuer, tokenPayLoad)
        val jwsObject = tokenHelper.getJWSObjectFromClaims(jwtClaims.toJSONString(), tokenConfiguration.accessTokenCategory)
        try {
            token = jwsObject.serialize()
        } catch (e: JOSEException) {
            throw Exception("Access Token : Unable to sign token", INTERNAL_SERVER_ERROR)
        } catch (t: Throwable) {
            throw Exception("Access Token : Unable to sign token: The JWS object must be in an unsigned state", INTERNAL_SERVER_ERROR)
        }
        return token
    }

    fun buildClaims(issuer: String, tokenPayLoad: TokenPayLoad): JSONObject {
        val jsonObject = JSONObject()
        val ttl: Long = tokenPayLoad.ttl
        jsonObject[TIME_TO_LIVE] = ttl

        // other token field assignments

        return jsonObject
    }
}

@JayAndromeda JayAndromeda changed the title Spring not initializing mockitobeans properly in Spring 3.3.4 kotlin test class Spring not initializing mockitobeans properly in Spring 3.4.4 kotlin test class Apr 28, 2025
@dmitrysulman
Copy link
Contributor

The code is still not runnable — some methods and dependencies are missing. To help speed up troubleshooting, please provide a sample project either as a ZIP archive or by sharing a link to a repository.

@JayAndromeda
Copy link
Author

JayAndromeda commented Apr 28, 2025

I had a feeling you would ask for this. I cant share most of the logic. I can try to extract it as a dummy project but I do feel as if enough is here to point in a direction that something isn't right in the meantime. If something is missing you can likely return a base object/blank where needed.

@sbrannen sbrannen added the in: test Issues in the test module label May 2, 2025
@sbrannen sbrannen changed the title Spring not initializing mockitobeans properly in Spring 3.4.4 kotlin test class @MockitoBean is not properly initialized in Kotlin test class with Spring Boot 3.4.4 May 2, 2025
@sbrannen
Copy link
Member

sbrannen commented May 2, 2025

Hi @JayAndromeda,

Thanks for reporting the issue, and congratulations on submitting your first issue for the Spring Framework! 👍

Unfortunately, the code snippets you have provided are not enough to go on.

Are you saying that your test setup used to work with Spring Boot 3.3.9 when using @MockBean?

Does your test setup work with Spring Boot 3.4.4 using @MockBean?

Did your test setup ever work using @MockitoBean (not @MockBean)?

In any case, in order to investigate this further, please provide a minimal application which demonstrates the behavior you are describing, preferably something that we can download and run such as complete Maven or Gradle project supplied as a ZIP file or a public Git repository that we can clone.

Thanks

@sbrannen sbrannen added the status: waiting-for-feedback We need additional information before we can continue label May 2, 2025
@JayAndromeda
Copy link
Author

Hi!

Sorry I was travelling the past few days and I do plan on separating this issue into its own repo for you guys soon. Just have to sit down and get it done in the next couple days.

Yes I did test with @Mockitobean as well as @MockBean and their respective versions that change when bringing along spring 3.4

Currently, I have rewritten our tests to longer Autowire the bean in the test case as to avoid the issue all together but still I want to see if this is a true issue or an issue with my old testing philosophy!

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels May 6, 2025
@bclozel bclozel added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels May 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module status: waiting-for-feedback We need additional information before we can continue status: waiting-for-triage An issue we've not yet triaged or decided on
Projects
None yet
Development

No branches or pull requests

5 participants