While working with Executor Service mocking is not working. Following is the code.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DemoClass {
public void demoMethod() {
ExecutorService executor = Executors.newFixedThreadPool(2);
List<MyUser> myUserList = new ArrayList();
myUserList.add(new MyUser("ABC"));
myUserList.add(new MyUser("XYZ"));
myUserList.forEach(transaction -> executor.submit(() -> processList(transaction)));
// this works well and print "mockedName"
// processList(new MyUser("withoutExecutor"));
executor.shutdown();
}
public void processList(MyUser user){
String name = MyEmployee.getEmployeeName();
System.out.println(name);
}
}
***********************************************
public class MyEmployee {
public static String getEmployeeName() {
return "testEmpName";
}
}
***********************************************
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import static org.mockito.Mockito.mockStatic;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class DemoClassTest {
private DemoClass demoClass;
private MockedStatic<MyEmployee> myEmployeeMockedStatic;
@Before
public void before() throws Exception {
demoClass = new DemoClass();
myEmployeeMockedStatic = mockStatic(MyEmployee.class);
}
@Test
public void myTest() {
// given
myEmployeeMockedStatic.when(MyEmployee::getEmployeeName).thenReturn("mockedName");
// when
demoClass.demoMethod();
}
@After
public void after() {
myEmployeeMockedStatic.close();
}
}
It is printing "testEmpName", desired result is "mockedName" Any static method called inside the calling of submit methods is not getting mocked. It could be because of threading in a pool, but how we can mock the static methods in this case?
Findings:
No any mock will work inside the executor.submit()
Reason of this is - mocking is not working on the different thread.
While we do executor.submit() - it starts the process on the different thread- that is the reason mocking is not working
I can see few posts that indicates that is not supported by the mocking till now. https://github.com/mockito/mockito/issues/2142
However I understand we can find some workaround - like we can mock executor and pass our required mocking in that mock. Still not sure on how to do.
Even if someone decodes the following for the above code. Referece: https://github.com/mockito/mockito/issues/2142
Executor executor = you executor....;
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation)
throws Exception {
Object[] args = invocation.getArguments();
Runnable runnable = (Runnable)args[0];
try (MockedConstruction<SomeClass> mockedConstructor = Mockito.mockConstruction(SomeClass.class);
MockedStatic<SomeStaticUtil> mockedUtil = mockStatic(SomeStaticUtil.class))
{
....do mocks things
runnable.run();
}
return null;
}
}).when(executor).execute(any());
One workaround is to pass in a different ExecutorService or Executor, which executes the tasks on the same thread.
Note that your code needs to be refactored a bit - you need to pass in Executor to your DemoClass, which will change it's runtime behaviour.
In your case, Executor is enough, so you can use simple implementation:
For more options, see Is there an ExecutorService that uses the current thread?
Entire implementation:
DemoClass
DemoClassTest
Notes:
getEmployeeNamemakes little sense - but I assume this is only an example