Hot questions for Using Mockito in executorservice
Question:
I have a class.
public class FeedServiceImpl implements FeedService { private final Map<FeedType, FeedStrategy> strategyByType; private final ExecutorService executorService = Executors.newSingleThreadExecutor(); public FeedServiceImpl(Map<FeedType, FeedStrategy> strategyByType) { if (strategyByType.isEmpty()) throw new IllegalArgumentException("strategyByType map is empty"); this.strategyByType = strategyByType; } @Override public void feed(LocalDate feedDate, FeedType feedType, String uuid) { if (!strategyByType.containsKey(feedType)) { throw new IllegalArgumentException("Not supported feedType: " + feedType); } executorService.submit(() -> runFeed(feedType, feedDate, uuid)); } private FeedTaskResult runFeed(FeedType feedType, LocalDate feedDate, String uuid) { return strategyByType.get(feedType).feed(feedDate, uuid); } }
How can I verify with Mockito that strategyByType.get(feedType).feed(feedDate, uuid)
was called when I call feed method?
@RunWith(MockitoJUnitRunner.class) public class FeedServiceImplTest { private LocalDate date = new LocalDate(); private String uuid = "UUID"; private FeedService service; private Map<FeedType, FeedStrategy> strategyByType; @Before public void setUp() { strategyByType = strategyByTypeFrom(TRADEHUB); service = new FeedServiceImpl(strategyByType); } private Map<FeedType, FeedStrategy> strategyByTypeFrom(FeedSource feedSource) { return bySource(feedSource).stream().collect(toMap(identity(), feedType -> mock(FeedStrategy.class))); } @Test public void feedTest() { service.feed(date, TH_CREDIT, uuid); verify(strategyByType.get(TH_CREDIT), timeout(100)).feed(date, uuid); } }
This is my version. But I don't want to use Mockito timeout method. It's in my opinion not a good solution. Help me please!
Answer:
When I test code that are dependent on executors I usually try to use an executor implementation that runs the task immediately in the same thread as submitted in order to remove all the hassle of multithreading. Perhaps you can add another constructor for your FeedServiceImpl
class that lets you supply your own executor? The google guava lib has a MoreExecutors.directExecutor()
method that will return such an executor. That would mean your test setup would change to something like:
service = new FeedServiceImpl(strategyByType, MoreExecutors.directExecutor());
The rest of the test code should then work as it is, and you can safely drop the timeout verification mode parameter.
Question:
Abstract:
I have a Spring @Component
that uses an autowired ExecutorService as a work pool. I'm using JUnit and Mockito to test the functionality of the component and I need to mock that Executor Service. This has been trivial for other autowired members - a generic helper, and a DAO layer for instance are easily mocked, but I need a real Executor Service.
Code:
@RunWith(MockitoJUnitRunner.class) public class MadeUpClassNameTest{ @Mock private ExecutorService executor; @Before public void initExecutor() throws Exception{ executor = Executors.newFixedThreadPool(2); } @InjectMocks private ASDF componentBeingAutowired; ...
This alone doesn't work, the results of invokeAll()
is always an empty list.
Attempting to more explicitly mock the executor method also doesn't work...
@Test public void myTestMethod(){ when(executor.invokeAll(anyCollection())) .thenCallRealMethod(); ... }
I get the cryptically worded exception:
You cannot use argument matchers outside of verification or stubbing.
(I thought this was a stubbing ?)
I could provide a thenReturn(Answer<>)
method, but I'd like to make sure that the code actually works with an executor, a fair bit of the code is devoted to mapping the results of Futures.
Problem How do I provide a real (or functionally usable mock) Executor Service ? Alternatively, is my difficulty in testing this component a sign that this is a poor design in need of refactoring, or possibly a bad test scenario ?
Notes I want to stress that my problem is NOT getting Mockito or Junit set up. Other mocks and tests work correctly. My problem is specific only to the particular mock above.
Using: Junit 4.12, Mockito 1.10.19, Hamcrest 1.3
Answer:
I think the following code runs after the Mock is injected.
@Before public void initExecutor() throws Exception{ executor = Executors.newFixedThreadPool(2); }
This causes your local copy of executor
to be set, but not the one that is injected.
I would recommend using constructor injection in on your componentBeingAutowired
and create a new one in your unit test and exclude Spring dependencies. Your test could then look like something below:
public class MadeUpClassNameTest { private ExecutorService executor; @Before public void initExecutor() throws Exception { executor = Executors.newFixedThreadPool(2); } @Test public void test() { ASDF componentBeingTested = new ASDF(executor); ... do tests } }
Question:
How can I mock executorService.submit() in the below scenerio. I have to mock
cacheController.someMethod(); but as submit method is called it creates a thread and cacheController.someMethod(); never gets called for test class.
@Autowired CacheController cacheController; protected static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(1); EXECUTOR.submit(() -> { try { cacheController.someMethod(); } catch (Exception e) { e.printStackTrace(); } });
Answer:
Basically you created hard to test code by relying on
protected static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(1);
In order to test that, you would have to use PowerMock(ito) dark magic to gain control over that call to the static method newFixedThreadPool(1)
here. In theory, that is nice and see, see here for example.
But: typically, when you do decent unit testing for Spring based environments, then you are probably already using another test runner, to get that @AutoWired thing working in your test setup. Adding PowerMock(ito) to that makes things much more complicated, and prone to errors.
Thus, the real answer is: rework your design, to not rely on that static method call. If you turn that thing into a normal field, you should be able to use "standard" mockito injection mechanisms, like outlined here.
Finally: I would also suggest to look into a same thread executor. Meaning: dont mock the service, but inject a specific service instance that simply calls your code on the same thread. Then you get quite more test coverage, but you avoid the most multi threading issues that normally give headaches in unit tests.
Question:
I am trying to unit test a code run containing executor service where the api is getting called twice or more depending on the no of devices in the list. When I try to unit test this from console, Mockito verify fails throwing an error that the Api is called only once while I passed list of devices. However, when I debug in intellij, it works correctly and gets executed and verified according to the no of devices in the list.
Following is the code
final ExecutorService executor = new ThreadPoolExecutor(MAX_THREADS, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); DeviceList.stream().forEach(device -> executor.execute(() -> GatewayToTest.deliver(device, id, testObject)));
Unit test code:
verify(GatewayToTest, times(devices.size())) .deliver(any(Device.class), anyString(), any(TestObject.class));
In the above code, GatewayToTest is called only once when I run unit tests in console.
Answer:
The executions run asynchronously, so you cannot guarantee that all the calls to GatewayToTest.deliver
happen before verify
.
Try to await for termination after submitting the tasks for execution:
executor.awaitTermination(10,TimeUnit.SECONDS);
Question:
How to write test case using mockito and junit for ExecuterService?
protected void updateRequest(String request) { ExecutorService executor = Executors.newFixedThreadPool(1); executor.submit(() -> { service.callGattuService(request); }); executor.shutdown(); }
Earlier this method was not Multithreaded and service.callGattuService() was called directly and following was test case.
@Test public void updateGattu() throws SystemException, SocketException, IOException { when(service.callGattuService("11")).thenReturn(something); testSubject.updateRequest(request) verify(service, times(1)).callGattuService("11"); }
I am not sure how to manipulate it so that ExecuterService can be detected/called.
Answer:
The simplest and straightforward solution in this situation is adding delay before verification without changing test logic because you're already checking that the internal method was called with particular argument no matter through executor or not.
@Test public void updateGattu() throws SystemException, SocketException, IOException { testSubject.updateRequest("11") verify(service, after(2*1000).times(1)).callGattuService("11"); }
Don't forget to spy your service. Hope it helps!
Edit: In the previous version of mockito-all (1.9.5) here is similar Mockito.timeout(int) method which could be used like so
@Test public void updateGattu() throws SystemException, SocketException, IOException { testSubject.updateRequest("11") verify(service, timeout(2*1000)).callGattuService("11"); }