Mocking companion object function in kotlin

10,450

What I ended up doing...

Instead of mocking the static method I ended up using PowerMockito's whenNew function to return a mocked instance of MockableClass. The final code looks something like this:

@RunWith(RobolectricTestRunner::class)
@Config(manifest = "src/main/AndroidManifest.xml",
        constants = BuildConfig::class,
        sdk = intArrayOf(23))
@PowerMockIgnore("org.mockito.*", "org.robolectric.*", "android.*")
@PrepareForTest(MockableClass::class)
class MyTest {

    private lateinit var context: Context

    @JvmField
    @Rule
    var rule = PowerMockRule()

    @Before
    fun setUp() {
        context = RuntimeEnvironment.application as Context
    }

    @Test
    fun test() {
        val instance = mock(MockableClass::class.java)
        instance.isValid = true
        whenNew<MockableClass>("com.example.MockableClass")
                .withAnyArguments()
                .thenReturn(instance)
        assertEquals(instance, MockableClass.getInstance(context))
    }
}
Share:
10,450

Related videos on Youtube

TheHebrewHammer
Author by

TheHebrewHammer

Updated on September 14, 2022

Comments

  • TheHebrewHammer
    TheHebrewHammer over 1 year

    I'm using PowerMock and Roboelectric and would like to mock a companion object function for a class. When I do this I get an error:

    org.mockito.exceptions.misusing.MissingMethodInvocationException: 
    when() requires an argument which has to be 'a method call on a mock'.
    For example:
        when(mock.getArticles()).thenReturn(articles);
    

    What I have is basically this:

    open class MockableClass private constructor(context: Context) {
    
        companion object {
    
            private val INSTANCE_LOCK = Any()
            private var sInstance: MockableClass? = null
    
            @JvmStatic
            fun getInstance(context: Context): MockableClass? {
                synchronized(INSTANCE_LOCK) {
                    sInstance = (sInstance ?: MockableClass(context).let {
                        if (it.isValid) it
                        else null
                    }
                }
                return sInstance
            }
        }
    
        init {
            // Do some initialization using context...
            // Set isValid to true/false depending on success
        }
    
        val isValid: Boolean
    }
    

    When I go to test this I will assume it will always work and would like to have getInstance just return a mocked version of the MockableClass.

    @RunWith(RobolectricTestRunner::class)
    @Config(manifest = "src/main/AndroidManifest.xml",
            constants = BuildConfig::class,
            sdk = intArrayOf(23))
    @PowerMockIgnore("org.mockito.*", "org.robolectric.*", "android.*")
    @PrepareForTest(MockableClass::class)
    class MyTest {
    
        private lateinit var context: Context
    
        @get:Rule
        val rule = PowerMockRule()
    
        @Before
        fun setUp() {
            context = RuntimeEnvironment.application as Context
        }
    
        @Test
        fun test() {
            val instance = mock(MockableClass::class.java)
            mockStatic(MockableClass::class.java)
            `when`(MockableClass.getInstance(Matchers.isA(Context::class.java)))
                    .thenReturn(instance)
            assertEquals(instance,
                    MockableClass.getInstance(RuntimeEnvironment.application as Context))
        }
    }
    

    I've also tried mocking MockableClass.Companion::class.java with no luck.

    Does anyone know what I need to do to be able to mock out this getInstance function?