I want to do something similar to 'MockUp' from JMockit but with Mockito.
I want to control the comportment of a method of a class that extends the class i want to test. But i have one problem that is the method is private, so i think i cant go with Mockito, and need use PowerMock.
The Problem
Class A extends B{...}
Class B {
private Header generateHeaderForServiceCall(c,d,f,g,h,j){...}
}
In my Class ATest{ In @Before i want to mock generateHeaderForServiceCall(.....) for just return a default Header created for me. }
So, using JMockit is like:
new MockUp<Controller>() {
@Mock
private Header generateHeaderForServiceCall(...) {
return defaultHeader;
}
};
I will specify better my context:
public class B {
private Header generateHeaderForServiceCall(Input A, Input B, Input c, Input D) throws ServiceException {
......
//do stuff
return header}
}
public class A extends B {
@Override
public Response process(Request request) throws SOAException {
//do stuff
try {
method_i_want_to_test(Input A, Input B);
} catch (Exception t) {
throwCorrectException(t, logger);
}
return response;
}
protected Dossier method_i_want_to_test(Input A, Input B) throws
SOAException {
... //do stuff
**Header** **header** = generateHeaderForServiceCall(Input A, Input
B,Input c, Input D);**
// **doLogic** with header returned and return the result
}
}
What im trying to do:
private A aTest;
@Before
public void setUp() throws Exception {
PowerMockito.mock(aTest);
PowerMockito.doReturn(defaultHeader).when(aTest,"generateHeaderForServiceCall", params);
}
So, when i go to method_i_want_to_test and call the generateHeaderForServiceCall i just want to get a default header, and ignore the inputs and the logic of the method. I want to mock this method, but its private/protected.
So, can i do with with Mockito?
Do i need to use PowerMock?
Can i use Mockito and PowerMockit together?
-------------------------------------- UPDATE ------------------------------
So, my classA, that i want to test is that :
package mypackage;
import package.ClassB;
@Service
public class ClassA extends ClassB implements Xinterface {
@Inject
public ClassA(InputA inputA, InputB inputB,InputC inputC, InputD inputD) {
...
}
@Override
public ClassAResponse process(ClassARequest request) throws SOAException {
ClassAResponse response = initResponse(inputA, request, new ClassAResponse());
ClassAInput input = request.getInput();
ClassAOutput output = new ClassAOutput();
response.setOutput(output);
try {
/* */
method_i_want_to_test(request.getHeader(), numberInput);
} catch (Exception t) {
throwCorrectException(t, logger);
}
return response;
}
protected Dossier method_i_want_to_test(Header srcHeader, Long numberInput) throws SOAException {
Header header = generateHeaderForServiceCall(inputA,srcHeader,inputF,inputJ,inputK);
OtherServiceRequest request = new OtherServiceRequest();
OtherServiceInput input = new OtherServiceInput();
input.setNumber(numberInput);
request.setInput(input);
request.setHeader(header); // So, you can see the i need the result of generateHeaderForServiceCall method
OtherServiceResponse response = OtherService.process(request);
assertSucessfullResponse(response, "OtherService");
return response;
}
}
My ClassB that contains private and protected methods is that:
package otherPackage;
...
public class ClassB {
private Header generateHeaderForServiceCall(InputA inputA,Header srcHeader,InputF inputF,InputJ inputJ,InputK inputK) throws ServiceException {
String[] nameInfo = QNameUtil.getServiceQNameInfo(inputA);
String serviceVersion = auxMethod(inputJ, inputF);
//... do more stuff
return result;
}
}
And my class of test, where i do test for private methods with PowerMock and try with Mockito if the method is protected. After that i will explain what i got when i run both tests:
package package;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.powermock.api.mockito.PowerMockito.doReturn;
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassA.class)
public class MyTest {
@InjectMocks
private ClassA classA;
@Mock
private InputA inputA;
@Mock
private InputB inputB;
@Mock
private InputC inputC;
@Mock
private InputD inputD;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
classA = new classA( inputA, inputB,inputC, inputD);
}
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = Aux.createDefaultHeader();
//create the spy of my ClassA
classA spy = PowerMockito.spy(classA);
// Define what I want the method 'generateHeaderForServiceCall' returns when called
doReturn(defaultHeader).when(spy, "generateHeaderForServiceCall", inputA,defaultHeader,inputF,inputJ,inputK);
// I try to call the method 'method_i_want_to_test' with classA variable @Injected and with spy of ClassA
//classA.method_i_want_to_test(defaultHeader,inputNumber);
spy.method_i_want_to_test(defaultHeader,inputNumber);
}
}
1 - when I Run this the processPrivateMethod test in debug method, when the generateHeaderForServiceCall is called, it tries execute the logic of the method and fails because the header is a basic one. But what i try to do is mock this and just return the default Header without logic.
2- If i change the generateHeaderForServiceCall for protected like some methods of ClassB, and use mockito for that:
@Test
public void processProtectedMethod() throws Exception{
defaultHeader = JUnitTestUtil.createDefaultHeader();
when(classA.generateHeaderForServiceCall(inputA,defaultHeader,"ccccccc","dxdx",5464564)).thenReturn(defaultHeader);
classA.method_i_want_to_test(defaultHeader,inputNumber);
}
But it return an error because the method is protected ( same error if it is private and i use mockito).
Error: java: generateHeaderForServiceCall(....) has protected access in package
Attempts:
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
// Partial mock to mock methods in parent class
child = new ClasseA(...){
@Override
protected Header generateHeaderForServiceCall(...) throws ServiceException {
//mock logic here
return aux.createDefaultHeader();;
}
};
}
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = aux.createDefaultHeader();
//when
Dossier bdoo = child.method_i_want_to_test(...);
}
2-
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = JUnitTestUtil.createDefaultHeader();
child = PowerMockito.spy(new ClasseA(...));
PowerMockito.doReturn(defaultHeader).when(child, "generateHeaderForServiceCall", context,defaultHeader,"ccccccc","dxdx",5464564);
//when
Dossier bdoo = child.method_i_want_to_test(...);
}
3-
@Test
public void processPrivateMethod() throws Exception{
defaultHeader = JUnitTestUtil.createDefaultHeader();
child = PowerMockito.spy(new ClassA(...));
father = PowerMockito.spy(new ClasseB());
PowerMockito.doReturn(defaultHeader).when(father, "generateHeaderForServiceCall", context,defaultHeader,"ccccccc","dxdx",5464564);
//when
Dossier bdoo = child.method_i_want_to_test(...);
}
Noone do what i want. All go into generateHeaderForServiceCall method in classB and trying do the logic inside. Thanks
Sounds like you are looking for a
spy.If its private you need to use
PowerMockito, if its protectedMockitoalone could handle it.PowerMockitois build uponMockito, so yes.Note that
spyshould be used sparingly, for example for testing legacy code. The usual recommondation would be to refactor your code.The
@PrepareForTestAnnotation needs to include theclasswhere the bytecode is modified in this caseClass A.Private method mocking with
PowerMockitoandJUnit4:Here a simplified example using a
Stringreturn instead of aHeader:Protected method mocking with
MockitoandJUnit5: