如何在测试期间通过Mockito验证是否调用了SUT的另一种公共方法

时间:2018-12-11 11:08:23

标签: java junit kotlin mockito

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

How to verify if method is called on System under test (not a mock)

我有一堂课

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()有一套完整的测试,可以完成繁重的工作。不幸的是,我不得不像a()(旧版代码)那样丑陋地思考,并且我不想复制所有测试。方法b()的。另外,这两个都需要公开。

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

2 个答案:

答案 0 :(得分:2)

您可以使用@SpyA使Mockito.spy()成为间谍。这将允许您调用和测试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);

答案 1 :(得分:2)

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

Mockito Java示例:

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

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

有关部分模拟,请参见模拟Documentation。不鼓励使用部分模拟,因为它不适合良好的OOP设计,但是在您的情况下,它符合其预期的目的,即测试困难的旧代码。

香草Mockito的Kotlin示例:

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

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

mockito-kotlin提供了一些扩展,这些扩展使您可以以更加科特林惯用的方式使用模仿。不幸的是,似乎没有一种以kotlin惯用的方式进行部分模拟的方法,但是可以在模仿者kotlin中实现,就像这样:

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

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

MockK是一个惯用的kotlin模拟库,允许间谍使用此功能。创建类的spy之后,您可以选择对方法进行存根:

val classUnderTest = spyk<A>()
every { classUnderTest.b() } returns 1L

classUnderTest.a()
verify { classUnderTest.b() }