使用Mockito和Kotlin的Base Presenter测试类 - 解决Generic类型擦除问题

时间:2018-03-09 11:50:09

标签: android kotlin mockito

我正在尝试编写一个带泛型的基础测试类来减少样板代码。它专门用于测试(MVP)演示者,我使用Mockito来模拟View界面。例如。像这样(简化):

abstract class BasePresenterTest<V: BaseView, P: BasePresenter<V>> {

    @Mock
    lateinit var mockView: V

    lateinit var presenter: P

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

    // ...
}

这是一个问题,因为类型擦除意味着Mockito无法模拟泛型参数中传递的具体View类型。尝试运行此类测试将在运行时生成java.lang.ClassCastException: BaseView$MockitoMock$1481956224 cannot be cast to ConcreteView

我目前的解决方法是添加一个抽象函数来返回View类,以便可以直接在基类中进行模拟:

abstract class BasePresenterTest<V: BaseView, P: BasePresenter<V>> {

    lateinit var mockView: V

    lateinit var presenter: P

    abstract fun getViewClass(): Class<V>

    @Before
    open fun setUp() {
        mockView = Mockito.mock(getViewClass())
    }

    // ...
}

这意味着具体测试类中的更多样板代码完全违背了基本测试类的目的。它也是泛型类型擦除的经典Java解决方法。我想知道Kotlin是否有更好的方法可以做到这一点? (我在某种程度上考虑了通用类型参数,但它们只适用于内联函数。)

1 个答案:

答案 0 :(得分:0)

在Kotlin中无法想到更好的方法,但我认为您应该重新考虑您的设计决策,并最终使用合成将您可能希望在不同演示者之间共享的任何代码移动到单独的类中。

为了保持通话的便捷性,您可以使这个常见的演示者类成为特定类的委托,如下所示:

class MyCommonPresenter : CommonPresenter {
    ...
}

class MySpecificPresenter internal constructor(common: CommonPresenter) 
    : CommonPresenter by common {
    constructor() = this(MyCommonPresenter())
    ...
}

然后您只需为MyCommonPresenter编写一个测试,并将其视为MySpecificPresenter测试的可模拟依赖项。