25

My code as below, refering to the solution in https://stackoverflow.com/a/30308199/3286489

import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.*

class SimpleClassTest {

    private fun <T> anyObject(): T {
        Mockito.anyObject<T>()
        return uninitialized()
    }

    private fun <T> uninitialized(): T = null as T
    lateinit var simpleObject: SimpleClass
    @Mock lateinit var injectedObject: InjectedClass


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

    @Test
    fun testSimpleFunction() {
        simpleObject = SimpleClass(injectedObject)

        verify(injectedObject).settingDependentObject(anyObject())

    }
}

I still have the below error

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method my.package.InjectedClass.settingDependentObject, parameter dependentObject

Did I miss anything?

UPDATED Below is the code tested (simplest form and working)

class SimpleClass(val injectedClass: InjectedClass) {

    fun simpleFunction() {
        injectedClass.settingDependentObject(DependentClass(Response.Builder().build()))
    }
}

open class DependentClass(response: Response) {

}

open class InjectedClass() {
    lateinit var dependentObject: DependentClass

    fun settingDependentObject(dependentObject: DependentClass) {
        this.dependentObject = dependentObject
    }
}

4 Answers 4

18

By default Kotlin classes and members are final. Mockito cannot mock final classes or methods. Thus when you write:

verify(injectedObject).settingDependentObject(anyObject())

the real implementation is called which requires non null argument.

To fix that either open your class and method or, even better, change SimpleClass to accept an interface as its constructor argument and mock the interface instead.

Sign up to request clarification or add additional context in comments.

6 Comments

My injectObject class is already an open class. The settingDependentObject require a non-null object, but anyObject() returns null. That's why I thought the solution in stackoverflow.com/a/30308199/3286489 would help me overcome the null required issue. But it's still not working.
@Elye please add the InjectedClass source to the question
Added the class to be tested to the Update above. Thanks!
@Elye you need to open both class and method for Mockito to work
Ya, open settingDependentObject, makes the things work great. Thanks!
|
1

There is a project specifically to help deal with Kotlin "closed by default" in unit testing with Mockito. For JUNIT, you can use the kotlin-testrunner which is an easy way to make any Kotlin test automatically open up classes for testing as they are loaded by the classloader. Usage is simple, just add one annotation of @RunWith(KotlinTestRunner::class), for example:

@RunWith(KotlinTestRunner::class)
class MyKotlinTestclass {
   @Test 
   fun test() {
   ...
   }
}

This is thoroughly covered in the article Never say final: mocking Kotlin classes in unit tests

This covers your use case in an automatic way by allowing all classes to be mocked that otherwise would not be allowed.

Comments

0

I ran into the same issue with Mockito when using RETURNS_DEEP_STUBS. It seems like nulls are still returned for nested objects, even when using the kotlin-allopen plugin.

Please check out and comment on this issue on Mockito if you're having the same problem.

Comments

-1

You can use this function instead

inline fun <reified T : Any> any(): T = Mockito.any(T::class.java) ?: T::class.java.newInstance()

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.