Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin lazy block not executed when using Mockito and InjectMocks [closed]

Tags:

mockito

kotlin

I'm using Mockito to test my Kotlin code. It's a web app and I use spring to inject values into some fields.

For example, my class snippet looks something like this:

class MyComponent {

    @Inject private lateinit var request: HttpServletRequest
    @Inject private lateinit var database: Database

To mimic this in my unit test I use the @Mock and @InjectMocks annotations from Mockito. So my test looks something like this:

class MyComponentTest {

    @Mock private lateinit var request: HttpServletRequest
    @Mock private lateinit var database: Database

    @InjectMocks private lateinit var sut: MyComponent

    @Before
    fun setup() {
       MockitoAnnotations.initMocks(this)
    }

Which all works fine. However, I also have a lazy initialization block in my component like this:

val user: User by lazy {
    database.findUser()
}

fun getUsername(): String {
    return user.name
}

When my test calls myComponent.getUsername() I would expect database.findUser() to be called as it initializes user but this doesn't happen.

If I put a breakpoint in the lazy block, it's never hit. Now I am assuming this is something to do with the way Mockito and @InjectMocks must 'touch' user but I don't really know. If I construct MyComponent manually then the lazy block is executed - but this won't inject my mocks.

How can I ensure the lazy block is called correctly from my test?

UPDATE: After a week absence, attempting to reproduce this without any changes and I could not. Can't explain it.

like image 316
Jumwah Avatar asked Oct 19 '22 12:10

Jumwah


1 Answers

I've tried to reproduce your problem and was not able to do so. This gist provides a working example.

However I would recommend revisiting the way you write tests. Consider following example:

class MyComponentTest {

    val request = mock<HttpServletRequest>()
    val database = mock<Database>()
    val sut = MyComponent(request, database)

    @Test
    fun username() {
        Mockito.`when`(database.findUser()).thenReturn(User("test"))

        val username = sut.getUsername()

        MatcherAssert.assertThat(username, Matchers.equalTo("test"))
    }
}

Which in my opinion is easier to understand than the one in mentioned the gist.

In case you're interested the mock helper function is a one liner:

inline fun <reified T : Any> mock() = Mockito.mock(T::class.java)

A full updated example can be found in this gist.

like image 106
miensol Avatar answered Oct 22 '22 02:10

miensol