Java 如何使用Mockito验证在测试期间调用了SUT的另一个公共方法

Java 如何使用Mockito验证在测试期间调用了SUT的另一个公共方法,java,junit,kotlin,mockito,Java,Junit,Kotlin,Mockito,我知道有重复的,但没有给出关于实际问题的答案 我有一门课: class A { public long a() { if(something) { return quicklyCalculatedResult } else { return b() run on separate thread, with this one blocked } } public long

我知道有重复的,但没有给出关于实际问题的答案

我有一门课:

class A {

    public long a() {
        if(something) {
            return quicklyCalculatedResult
        } else {
            return b() run on separate thread, with this one blocked
        }
    }

    public long b() {} //doStuffOnCurrentThread;

}
我有一套完整的b()测试,它完成了繁重的工作。不幸的是,我不得不像一个()一样思考(遗留代码),我不想复制所有的测试。方法b()中的。此外,这两项都需要公开


我想验证在某些情况下,a()调用b(),但我不能这样做,因为被测试的类不是模拟类。我需要一种方法来验证该方法是在真实对象上调用的,而不仅仅是在模拟对象上。

您可以使用或
Mockito.spy()使
a
成为间谍。这将允许您调用和测试
a()
方法逻辑,但也可以用不变量替换
b()
。这可以用一个列表来说明:

List list = new LinkedList();
List spy = Mockito.spy(list);

// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");

// You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

您可以使用或
Mockito.spy()
使
A
成为间谍。这将允许您调用和测试
a()
方法逻辑,但也可以用不变量替换
b()
。这可以用一个列表来说明:

List list = new LinkedList();
List spy = Mockito.spy(list);

// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");

// You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

Mockito和其他kotlin模拟库提供部分模拟或类似功能。您可以指定要调用的实际方法,而其他方法保留存根:

Mockito java示例:

A classUnderTest = mock(A.class);
when(classUnderTest.a()).thenCallRealMethod();

classUnderTest.a();
verify(classUnderTest).b()
请参阅关于部分模拟的mockito。不鼓励部分模拟,因为它不适合良好的OOP设计,但在您的情况下,它符合其预期目的,即测试困难的遗留代码

Kotlin与香草Mockito的示例:

val classUnderTest = mock(A::class.java)
`when`(classUnderTest.a()).thenCallRealMethod()

classUnderTest.a()
verify(classUnderTest).b()
提供扩展,允许您以更为kotlin惯用的方式使用mockito。不幸的是,似乎没有一种方法可以用kotlin惯用的方式进行部分模拟,但可以用mockito kotlin实现,如下所示:

val classUnderTest = mock<A>()
doCallRealMethod().whenever(classUnderTest).a()

classUnderTest.a()
verify(classUnderTest).b()

Mockito和其他kotlin模拟库提供部分模拟或类似功能。您可以指定要调用的实际方法,而其他方法保留存根:

Mockito java示例:

A classUnderTest = mock(A.class);
when(classUnderTest.a()).thenCallRealMethod();

classUnderTest.a();
verify(classUnderTest).b()
请参阅关于部分模拟的mockito。不鼓励部分模拟,因为它不适合良好的OOP设计,但在您的情况下,它符合其预期目的,即测试困难的遗留代码

Kotlin与香草Mockito的示例:

val classUnderTest = mock(A::class.java)
`when`(classUnderTest.a()).thenCallRealMethod()

classUnderTest.a()
verify(classUnderTest).b()
提供扩展,允许您以更为kotlin惯用的方式使用mockito。不幸的是,似乎没有一种方法可以用kotlin惯用的方式进行部分模拟,但可以用mockito kotlin实现,如下所示:

val classUnderTest = mock<A>()
doCallRealMethod().whenever(classUnderTest).a()

classUnderTest.a()
verify(classUnderTest).b()

我想如果b被叫到你不必担心。相反,关注导致b被调用的条件(“某物”条件的否定),然后验证您是否得到了预期的结果。模拟的要点是允许您简化/控制与未测试类的依赖关系/耦合。此外,即使您不想,也应该将测试迁移到需要关注b的b上。@JasonArmstrong嘿,这是一种方法,但有许多条件可能导致调用b()。在我的真实示例中,它更像是“如果某个参数为null,那么给出一个快速的答案,在任何其他情况下得到b()的结果”。b()将根据给定的参数以多种方式响应。因此,要用返回值检查这一点,而不是检查是否调用了b(),我必须测试多个场景,这基本上是复制b()的测试…我理解你的意思,但你在a点或b点上真正的单元测试是什么?@JasonArmstrong虽然我原则上同意你的说法,有时我们不得不测试困难的遗留代码。这就是部分嘲笑的原因。@Dean我听说你也同意,有时候我们不得不选择一条不受欢迎的道路,我只是想提醒大家注意,这样当其他人看到这个问题时,他们可以做出明智的选择。嗯,如果b被叫到,我想你不必担心。相反,关注导致b被调用的条件(“某物”条件的否定),然后验证您是否得到了预期的结果。模拟的要点是允许您简化/控制与未测试类的依赖关系/耦合。此外,即使您不想,也应该将测试迁移到需要关注b的b上。@JasonArmstrong嘿,这是一种方法,但有许多条件可能导致调用b()。在我的真实示例中,它更像是“如果某个参数为null,那么给出一个快速的答案,在任何其他情况下得到b()的结果”。b()将根据给定的参数以多种方式响应。因此,要用返回值检查这一点,而不是检查是否调用了b(),我必须测试多个场景,这基本上是复制b()的测试…我理解你的意思,但你在a点或b点上真正的单元测试是什么?@JasonArmstrong虽然我原则上同意你的说法,有时我们不得不测试困难的遗留代码。这就是部分嘲笑的原因。@Dean我听说你和我都同意,有时候我们不得不选择一条不受欢迎的道路,我只是想提醒大家注意,这样当其他人看到这个问题时,他们可以做出明智的选择。嘿,谢谢!我在让它工作方面没有什么困难,但这只是因为使用了Kotlin而不是Java。这正是我所需要的:)嘿,谢谢!我在让它工作方面没有什么困难,但这只是因为使用了Kotlin而不是Java。这正是我所需要的:)谢谢!它起作用了,我投了赞成票。我给@Dean的答案是正确的,因为他的答案更接近于问题,也更接近于提出。thenCallRealMethod(),但你的方法同样有效!谢谢它起作用了,我投了赞成票。我给@Dean的答案是正确的,因为他的答案更接近于问题,也更接近于提出。thenCallRealMethod(),但你的方法同样有效!