在Kotlin中模拟伴生对象函数

12

我正在使用PowerMock和Roboelectric,希望模拟一个类的伴生对象函数。但是当我这样做时,会出现错误:

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);

我拥有的基本上就是这样:

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
}

测试时,我会假设它总是有效的,并希望 getInstance() 只返回 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))
    }
}

我也尝试了模拟 MockableClass.Companion::class.java 但没有成功。

有人知道我需要做什么才能模拟这个 getInstance 函数吗?


我会删除Robolectric标签,因为这只是关于Kotlin和反射的问题。 - Eugen Martynov
好的,我不确定类加载器是否与此有关。 - TheHebrewHammer
1个回答

5

最终我采用了PowerMockito的whenNew函数来返回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

    @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))
    }
}

三天后使用这个,这绝对有所帮助。谢谢! - Rafael Ruiz Muñoz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接