【问题标题】:Mockito Stubbed Spy sometimes calls and sometimes does not call the spied object methodsMockito Stubbed Spy 有时会调用,有时不会调用被监视的对象方法
【发布时间】:2018-02-17 07:55:49
【问题描述】:

问题

@Test,我怎样才能同时实现;

  1. 从被测的 Kotlin 类中调用真实方法并
  2. 将内部调用存根到此类被测类中的其他方法。

场景

我正在使用以下库;

testCompile "com.nhaarman:mockito-kotlin:1.5.0"
testCompile "org.mockito:mockito-inline:2.12.0"

我也有一个简单的 kotlin 类

class MyClass() {

    fun parentFunc() {
        funA()
    }

    fun funA() {
        //DOES SOMETHING WHICH I ASSUME IS IRRELEVANT FOR ANSWERING THE QUESTION
    }
}

用间谍进行测试

@Test
fun myTest() {
    val myClassSpy = spy(MyClass())
    Mockito.doNothing().`when`(myClassSpy.funA())
    //Mockito.doNothing().whenever(myClassSpy.funA()) also throws the same error

    myClassSpy.parentFunc()

    verify(myClassSpy, times(1)).funA()
}

哪个会引发错误,

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.nhaarman.mockito_kotlin.MockitoKt.doNothing(Mockito.kt:108)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, which is not supported
 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

另一个测试用例;

@Test
fun myTest() {
    val myClassSpy = Mockito.spy(MyClass())

    myClassSpy.parentFunc()

    verify(myClassSpy, times(1)).funA()
}

给出以下错误:

Wanted but not invoked:
myClass.funA();

However, there was exactly 1 interaction with this mock:
myClass.parentFunc();

此外,每当我尝试使用调试器调用 myClassSpy 方法或与之相关的东西时,它都会引发以下错误:

com.sun.jdi.InternalException : Unexpected JDWP Error: 41

我尝试过使用

Mockito.`when`(myClassSpy.funA()).then { }
Mockito.`when`(myClassSpy.funA()).thenAnswer { }
Mockito.`when`(myClassSpy.funA()).thenReturn(Unit)

使用模拟测试

在这种情况下模拟整个类不起作用,因为它是一个模拟并且不调用被测的真实方法:

@Test
fun myTest() {
    val myMock: MyClass = mock()

    myMock.parentFunc()

    verify(myMock, times(1)).funA()
}

同样的错误:

Wanted but not invoked:
myClass.funA();

However, there was exactly 1 interaction with this mock:
myClass.parentFunc();

如果我进一步调用真正的方法,它也会显示相同的wanted but not invoked myClass.funA(); 错误:

@Test
fun myTest() {
    val myMock: MyClass = mock()

    Mockito.`when`(myMock.parentFunc()).thenCallRealMethod()

    myMock.parentFunc()

    verify(myMock, times(1)).funA()
}

我也尝试打开MyClass,但也出现了同样的错误。

因此,我如何对间谍的方法进行存根,以便当我测试来自此类间谍对象的方法时,它不会将调用传播到我不想进一步模拟的其他方法。

非常感谢任何帮助、建议、想法...以测试这些类型的方法。

【问题讨论】:

  • 使用 spy 进行测试时,when 方法必须获取 spy 对象而不是其方法作为参数。你应该打电话给Mockito.doNothing().when(myClassSpy).funA()

标签: android unit-testing kotlin mockito


【解决方案1】:

对我来说,用 mockito 模拟 kotlin 类有时有效,有时无效,所以我通常做的是为该类提取一个,这总是有效的。

mock 也用于测试交互,所以你不应该在你正在测试的同一个类上模拟一个方法,而是你传递给构造函数的不同类(依赖注入)然后你可以在测试时注入一个模拟和正确的生产时的依赖。

class MyTestedClass(val funManager:MyUsedClass) {    
    fun parentFunc() {
        funManager.funA()
    }
}

【讨论】:

    【解决方案2】:

    解决方案:

    • 当代码库全部在 Kotlin 中时,解决方案是:
      使用 MockK,这是一个用于测试和模拟 Kotlin 代码的库。
    • 当代码库用 Java 和 Kotlin 编写时,解决方案是:
      使用 MockK 测试和模拟 Kotlin,使用 Mockito 测试和模拟 Java 代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      相关资源
      最近更新 更多