Verify that overriden superclass method is called when invoking this method on subclass

Pawel P. picture Pawel P. · Mar 13, 2014 · Viewed 9.2k times · Source

I'll show my problem using this example:
I have a class with a method foo. That class has a subclass which overrides this method.
Subclass' method calls superclass' method. Can I verify that?
I don't want to test what foo in superclass does. I just need to verify that it was called. I know that refactoring could help (favour composition over inheritance, etc) but I am unable to do that.
Is there any way to achieve what I need?
Below is simple example of what I've tried

package tmp;
import org.junit.Test;
import org.mockito.Mockito;
import static org.mockito.Mockito.times;

public class Example {
    @Test
    public void test() {
        // given
        ChildClass childClass = new ChildClass();
        ChildClass spyChildClass = Mockito.spy(childClass);
        // when
        spyChildClass.foo(100);
        // then
        Mockito.verify((BaseClass) spyChildClass, times(1)).foo(101);
    }
}

abstract class BaseClass {
    public void foo(int n) {
        System.out.printf("BaseClass.foo(%d)%n", n);
    }
}

class ChildClass extends BaseClass {
    @Override
    public void foo(int n) {
        System.out.printf("ChildClass.foo(%d)%n", n);
        super.foo(n + 1);
    }
}

And this is the result:

ChildClass.foo(100)
BaseClass.foo(101)

Argument(s) are different! Wanted:
childClass.foo(101);
-> at tmp.Example.test(Example.java:19)
Actual invocation has different arguments:
childClass.foo(100);
-> at tmp.Example.test(Example.java:16)

Expected :childClass.foo(101);
Actual   :childClass.foo(100);
   <Click to see difference>

Obviously it's not what I wanted to see.

I can't modify BaseClass. I don't want to test BaseClass (I am not responsible for it). I don't even neet to know what exactly it does. I just need to verify that its method was called. Wnything else is not my problem. Its the problem of people who maintain BaseClass.

Answer

jmkgreen picture jmkgreen · Mar 13, 2014

Test the behaviour of the class, not it's implementation.

Write the test such that the method is called and is expected to do something. Next check the object now represents what you now expect it to represent.

If BaseClass.foo is expected to increment some counter by 100, yet Subclass.foo increments some counter by 50 then calls the superclass, verify that the counter is now 150 and not just 50.

Don't peek the how - they may change over time. Do test the behaviour. The method foo may do other things besides increase counters - check the state of the object not what it did.