9

How to use Mockito or PowerMock to mock a protected method that is realized by a subclass, but inherited from an abstract super class?

In other words, I want to test "doSomething" method while mocking the "doSomethingElse".

Abstract super class

public abstract class TypeA {

    public void doSomething() {     

        // Calls for subclass behavior
        doSomethingElse();      
    }

    protected abstract String doSomethingElse();

}

Subclass implementation

public class TypeB extends TypeA {

    @Override
    protected String doSomethingElse() {
        return "this method needs to be mocked";
    }

}

Solution

Answers given here are correct and will work if classes involved are in the same package.

But if different packages are involved one option is to user PowerMock. The following example worked for me. Of course there might be other ways of doing it, this is one that works.

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ TypeB.class })
public class TestAbstract {

    @Test
    public void test_UsingPowerMock() throws Exception {
        // Spy a subclass using PowerMock
        TypeB b = PowerMockito.spy(new TypeB());
        String expected = "some value for mock";

        // Mock a method by its name using PowerMock again
        PowerMockito.doReturn(expected).when(b, "doSomethingElse");

        // Calls the 
        String actual = b.doSomething();
        assertEquals(expected, actual);     

    }
}

Note: Tests done using Java 5, jUnit 4.11, Mockito 1.9.0 and PowerMock 1.4.12.

Evandro Pomatti
  • 13,341
  • 16
  • 97
  • 165
  • 2
    This approach gives me a `NullPointerException` with Java 8, JUnit 4.12, and PowerMock 1.6.4. – Mack Apr 26 '16 at 21:21
  • @Mack did you solve it? – ceyun Jun 03 '20 at 20:14
  • 1
    @ceyun I apologize but it's been so long I don't recall if I solved it, or if I did, how. Perhaps one of the individuals who upvoted my comment recall? – Mack Jun 05 '20 at 12:13

4 Answers4

6

You can use Mockito.CALLS_REAL_METHODS when mocking the abstract method. This will call the originals methods of the class and you can mock all abstract methods by yourself.

TypeA typeA = mock(TypeA.class, Mockito.CALLS_REAL_METHODS);
when(typeA.doSomethingElse()).thenReturn("Hello");
typeA.doSomething();

Or you test directly on the TypeB with a spy:

TypeB typeB = spy(new TypeB());
when(typeB.doSomethingElse()).thenReturn("Hello");
typeB.doSomething();
mszalbach
  • 10,612
  • 1
  • 41
  • 53
  • 2
    The 1st option fails because TypeA is abstract. Option 2 works with `spy()` but when I try to apply it into my production code it gives me `The method from the type is not visible`. Trying to figure out why. – Evandro Pomatti Aug 18 '15 at 14:20
  • Actually your test is correct, but I have classes that are in different packages, that is why I was not able to do it earlier. Methods are not visible from other packages when protected. – Evandro Pomatti Aug 18 '15 at 14:27
  • Did the 1st option works too? I have tested both with Mockito 1.10.19 and latest beta version and both work as expected. – mszalbach Aug 18 '15 at 14:32
  • Indeed it works. Forgot to tell you my Mockito version is ancient, 1.9.0, because of Java 5. – Evandro Pomatti Aug 18 '15 at 14:37
4

I suggest using Mockito for that:

// Create a new Mock
final TypeA a = Mockito.mock(TypeA.class, Mockito.CALLS_REAL_METHODS);

// Call the method
a.doSomething();

// Now verify that our mocked class' method was called
Mockito.verify(a, Mockito.times(1)).doSomethingElse();
Florian Schaetz
  • 10,454
  • 5
  • 32
  • 58
  • It works, but I just realized that I have classes in different packages in my production code. Protected methods are not visible then. – Evandro Pomatti Aug 18 '15 at 14:29
  • This makes it a problem. A possible solution would be to use PowerMock, which should be able to verify private methods, afaik. Never used it, though. – Florian Schaetz Aug 18 '15 at 14:30
3

You can test your abtract class using mockito in the following way

TypeA typA = Mockito.mock(TypeA.class, Mockito.CALLS_REAL_METHODS);
when(typA.doSomethingElse()).thenReturn("doSomethingElse");
Assert.assertSomething(typeA.doSomething());
jozzy
  • 2,863
  • 3
  • 15
  • 12
0

To mock methods that returns void in abstract classes we could use:

MyAbstractClass abs = Mockito.mock(MyAbstractClass.class);
Mockito.doNothing().when(abs).myMethod(arg1,arg2....));

We can replace arguments with Mockito.anyString() etc as per requirements.

Aftab
  • 2,863
  • 32
  • 41