Michał Powłoka
Michał Powłoka

Reputation: 1511

How to verify with Mockito that another public method of SUT was called during test

I am aware of duplicate, bo no answer about actual question was given there.

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

I have a class:

class A {

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

    public long b() {} //doStuffOnCurrentThread;

}

I have a complete set of tests for b(), which does the heavy lifting. Unfortunately I have to make an ugly think like a() (legacy code) and I don't want to copy all the tests. Of method b(). Also, both of these need to be public.

I want to verify that under certain circumstances a() calls b(), but I cannot do that, beacause tested class is not a mock. I need a way to verify that method was called on a real object, not only a mock.

Upvotes: 0

Views: 1914

Answers (2)

Dean
Dean

Reputation: 2015

Mockito and other kotlin mocking libraries provide partial mocking or similar functionality. You can specify real methods to be called, while the other methods remain stubs:

Mockito java example:

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

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

See the mockito Documentation on partial mocking. Partial mocking is not encouraged because it does not fit good OOP design, but in your case it fit its intended purpose, which is to test difficult legacy code.

Kotlin example with vanilla Mockito:

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

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

mockito-kotlin provides extensions that allow you to use mockito in a more kotlin idiomatic way. Unfortunately there does not appear to be a way to do partial mocking in a kotlin idiomatic way, but it can be achieved in mockito-kotlin like so:

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

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

MockK, an idiomatic kotlin mocking library, allows for this functionality with spys. After creating a spy of the class you can choose to stub methods:

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

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

Upvotes: 4

Karol Dowbecki
Karol Dowbecki

Reputation: 44960

You can make A a spy with @Spy or Mockito.spy(). This will allow you to invoke and test a() method logic but also replace b() with an invariant. This can be illustrated with a list:

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);

Upvotes: 2

Related Questions