Reputation: 19260
I’m using Mockito 1.9.5. How do I mock what is coming back from a protected method? I have this protected method …
protected JSONObject myMethod(final String param1, final String param2)
{
…
}
However, when I attempt to do this in JUnit:
final MyService mymock = Mockito.mock(MyService.class, Mockito.CALLS_REAL_METHODS);
final String pararm1 = “param1”;
Mockito.doReturn(myData).when(mymock).myMethod(param1, param2);
On the last line, I get a compilation error “The method ‘myMethod’ is not visible.” How do I use Mockito to mock protected methods? I’m open to upgrading my version if that’s the answer.
Upvotes: 61
Views: 131455
Reputation: 1716
package com.mypackage;
public class MyClass {
protected String protectedMethod() {
return "Can't touch this";
}
public String publicMethod() {
return protectedMethod();
}
}
package com.mypackage;
import org.junit.Before;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
private MyClass myClass;
private MyClass spyMyClass;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
myClass = new MyClass();
spyMyClass = spy(myClass);
doReturn("Something").when(spyMyClass)
.protectedMethod();
}
@Test
testPublicMethod(){
AssertThat(spyMyClass.publicMethod()).isEqualTo("Something");
}
}
doReturn and spy are important here
Upvotes: 0
Reputation: 968
MyService myService = new MyService() {
MyService callProtectedMethod(String param1, String param2) {
myMethod(param1, param2);
return this;
}
}.callProtectedMethod(param1, param2);
// your assertion here: trivial e.g. assertNotNull(myService);
Upvotes: 0
Reputation: 805
Something like following worked for me, using doReturn() and Junit5's ReflectionSupport.
[Note: I tested on Mockito 3.12.4]
ReflectionSupport.invokeMethod(
mymock.getClass()
// .getSuperclass() // Uncomment this, if the protected method defined in the parent class.
.getDeclaredMethod("myMethod", String.class, String.class),
doReturn(myData).when(mymock),
param1,
param2);
Upvotes: 5
Reputation: 3725
public class Test extend TargetClass{
@Override
protected Object method(...) {
return [ValueYouWant];
}
}
In Spring, you can set it high high-priority like this:
@TestConfiguration
public class Config {
@Profile({"..."})
@Bean("...")
@Primary // <------ high-priority
public TargetClass TargetClass(){
return new TargetClass() {
@Override
protected WPayResponse validate(...) {
return null;
}
};
}
}
It is the same to override the origin bean.
Upvotes: -1
Reputation: 301
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!");
}
}
Upvotes: 28
Reputation: 686
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));
}
}
Upvotes: 15
Reputation: 977
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:
Upvotes: 0
Reputation: 32969
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:
Upvotes: 62