Home > Net >  MockK test member function getting NullPointerException
MockK test member function getting NullPointerException

Time:08-12

The class under test looks like:

class State(pivate val repo){
    val values = listOf<Int>()
    fun update() {
        values = repo.generateValues() // <-line 375
    }
}

The unit test looks like:

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
private class StateTest {
    @MockK(relaxed = true) private lateinit var mockedRepo: Repo
    @BeforeAll
    fun config() {
        MockKAnnotations.init(this)
    }

    @BeforeEach
    fun setup() {
        clearAllMocks()
        unmockkAll()
    }

    @Test
    fun `invoke update`() {
        val state = mockk<State>(relaxed = true)

        every { state.repo } answers { mockedRepo }
        every { mockedRepo.generateValues() } returns listOf(1,2,3)
        every { state.update() } answers { callOriginal() }

        state.update()
        Assertions.assertTrue(state.values.size > 0)
    }
}

Runnig the test, a NullPointerException is thrown:

java.lang.NullPointerException
    at com.name.someapp.someservice.State.update(State.kt:375)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at io.mockk.proxy.jvm.advice.MethodCall.call(MethodCall.kt:14)
    at io.mockk.proxy.jvm.advice.SelfCallEliminatorCallable.call(SelfCallEliminatorCallable.kt:14)
    at io.mockk.impl.instantiation.JvmMockFactoryHelper.handleOriginalCall(JvmMockFactoryHelper.kt:95)
    at io.mockk.impl.instantiation.JvmMockFactoryHelper.access$handleOriginalCall(JvmMockFactoryHelper.kt:18)
    at io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1$invocation$$inlined$stdFunctions$lambda$1.invoke(JvmMockFactoryHelper.kt:27)
    at io.mockk.impl.stub.MockKStub$handleInvocation$originalPlusToString$1.invoke(MockKStub.kt:230)
    at io.mockk.MockKAnswerScope.callOriginal(API.kt:2205)

CodePudding user response:

The reason you're getting the NullPointerException is that fun update() does not call getRepo() (which you've mocked) but instead it uses the backing field repo directly. (You can see this by compiling the Kotlin source to bytecode and decompiling to Java in IntelliJ IDEA.) This is also documented at kotlinlang.org:

ⓘ On the JVM: Access to private properties with default getters and setters is optimized to avoid function call overhead.

The answer is, as sidgate said in the comment, to create a real (not mock) instance of State and pass the mock repo to it constructor:

val state = State(mockRepo)

It is a code smell to mock the "system under test".

  • Related