繁体   English   中英

Mockito模拟有多少模拟?

[英]How much of a mock is a Mockito mock?

我保证,这是一个严重的问题。 我花了最后两个小时阅读了我能找到的尽可能多的Mock定义,但没有一个向我解释。

我有一个要测试的类,该类需要一个mapper类作为其主要构造函数的一部分:

open class PoiListViewModel @Inject constructor(
        private val mapper: PoiMapper
) : ViewModel() {

在单元测试中,我有以下代码:

//Mock objects needed to instantiate the class under test
@Mock lateinit var mapper: PoiMapper

// Class being tested
lateinit var poiListViewModel: PoiListViewModel

@Before
fun setup() {
    MockitoAnnotations.initMocks(this)
    poiListViewModel = PoiListViewModel(mapper)
}

我对所有聪明的开发人员的问题是,什么是模拟游戏? 具体来说,它可以复制多少原始班级?

我会告诉你我的假设定义。 模拟是一个伪造的替代类,它代表我的真实类, 但它除了跟踪要向其发送哪些方法调用之外,什么也不做。 如果我希望模拟具有任何功能,则需要将该功能存入其中。

至少那是我对模拟的无知观点。 但是我显然很生气,因为在我的单元测试中,我的“模拟”映射器类似乎是一个实际的映射器类。 如果调试单元测试,我会看到它遍历了我的mapper类的所有代码。 我看到它返回转换后的数据。

这是mapper类代码(如果有关系的话):

open class PoiMapper @Inject constructor() {

    fun mockTest(num: Int): Int{
        return num *23
    }

    fun mapToPresentation(domainModel: Poi_Domain): Poi_Presentation {

        var test = 3
        var results = mockTest(test)

        return Poi_Presentation(domainModel.id,domainModel.name,domainModel.description,
                domainModel.img_url,domainModel.latitude,domainModel.longitude,domainModel.imgFocalpointX,
                domainModel.imgFocalpointY,domainModel.collection,domainModel.collectionPosition,
                domainModel.release,domainModel.stampText)
    }
}

有人可以向我解释一下,Mockito模拟有多少模拟? 我是否没有正确实例化模拟? 有人可以给我一个更好的方式来思考模拟,以便我可以将所有这些都包裹住吗?

您对模拟的理解是正确的。 作为Mockito的实现细节,您正在碰到Kotlin的默认默认行为。

Mockito模拟(不同于Mockito间谍)被定义为代替您的类实例。 除非您将它们存根否则返回它们,否则它们会记录所有交互并返回默认的伪值(零,空字符串,空列表,空值等)。 您可以通过对返回值( when / thenReturn )进行存根,对方法的特定行为( when / thenAnswer )或检查某些方法是否被调用( verify )并检索特定的方法来确认它们与被测系统正确协作。它们被(ArgumentCaptor)调用的实例。

幕后,Mockito通过生成您要模拟的类的子类,并重写所有委托给Mockito内部处理程序的方法来实现此目的。 这就是赋予Mockito静默覆盖行为的能力的原因:被测系统认为它正在调用您的依赖关系,但是您的代码正在使用Java的虚拟方法分派来覆盖依赖关系的行为。

诀窍是:Java方法默认是虚拟的,除非您将它们标记为final 在Kotlin中,功能默认情况下关闭的,除非您将其标记为open (我将继续称它们为final ,因为这是JVM或Android Dexer中正在起作用的定义,该定义正在读取Kotlin生成的字节码。)当虚拟机确定基于静态类型的引用的类型时,并且您正在调用final方法,则允许编译器内联该实现的代码(JLS 8.4.3.3),因为您断言该方法不能被覆盖,并且任何尝试覆盖该方法的代码都将在编译时失败。 Mockito生成的代码不是用这种方式编译的,Mockito无法检测到这种情况。

在您的情况下, mapToPresentationopen ,因此编译器将其视为final ,并且不保留将使Mockito覆盖行为的虚拟方法分派。 您对模拟的定义是正确的,您的代码也将是正确的,除了Kotlin是默认关闭的,而Java是默认打开的。 此外,您确实依赖于open的函数,因为您希望使用与函数中的实现不同的实现来调用它。

琐碎地,您可以open要覆盖的所有功能,或者使用Mockito 2.1+的内置功能模拟最终方法 但是,作为一般的最佳实践,您希望对象的行为类似于PoiMapper,即使它没有遵循特定的PoiMapper实现。 这可能是接口/ Impl拆分的一个很好的理由,例如您的PoiListViewModel类采用了PoiMapper接口。 在生产中,您可以按需提供PoiMapperImpl,但是Mockito可以生成PoiMapper接口的任意实现,而不必担心PoiMapperImpl及其功能是打开还是关闭。

您是否添加了注释

@RunWith(MockitoJUnitRunner.class)

参加你的考试班?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM