How do I use Mockito to mock a protected method?

Responding to the request for a code sample of option 3 from John B's answer:


public class MyClass {
    protected String protectedMethod() {
        return "Can't touch this";
    }
    public String publicMethod() {
        return protectedMethod();
    }
}

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    class MyClassMock extends MyClass {
        @Override
        public String protectedMethod() {
            return "You can see me now!";
        }
    }

    @Mock
    MyClassMock myClass = mock(MyClassMock.class);

    @Test
    public void myClassPublicMethodTest() {
        when(myClass.publicMethod()).thenCallRealMethod();
        when(myClass.protectedMethod()).thenReturn("jk!");
    }
}

You can use Spring's ReflectionTestUtils to use your class as it is and without needing of change it just for tests or wrap it in another class.

public class MyService {
    protected JSONObject myProtectedMethod(final String param1, final String param2) {
        return new JSONObject();
    }

    public JSONObject myPublicMethod(final String param1) {
        return new JSONObject();
    }
}

And then in Test

@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {
    @Mock
    private MyService myService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        when(myService.myPublicMethod(anyString())).thenReturn(mock(JSONObject.class));
        when(ReflectionTestUtils.invokeMethod(myService, "myProtectedMethod", anyString(), anyString())).thenReturn(mock(JSONObject.class));
    }
}

This is not an issue with Mockito, but with plain old java. From where you are calling the method, you don't have visibility. That is why it is a compile-time issue instead of a run-time issue.

A couple options:

  • declare your test in the same package as the mocked class
  • change the visibilty of the method if you can
  • create a local (inner) class that extends the mocked class, then mock this local class. Since the class would be local, you would have visibility to the method.

John B is right, this is because the method you're trying to test is protected, it's not a problem with Mockito.

Another option on top of the ones he has listed would be to use reflection to gain access to the method. This will allow you to avoid changing the method you are testing, and avoid changing the pattern you use to write tests, and where you store these tests. I've had to do this myself for some tests where I was not allowed to change the existing code base which included a large number of private methods that needed to be unit tested.

These links explain Reflection and how to use it very well, so I will link to them rather than copy:

  • What is reflection and whit is it useful
  • How to test a class that has private methods, fields, or inner classes