Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to verify a mock method running in different thread in Mockito?

I have a method like the following,

public void generateCSVFile(final Date billingDate) {     asyncTaskExecutor.execute(new Runnable() {         public void run() {             try {                 accessService.generateCSVFile(billingDate);             } catch (Exception e) {                 LOG.error(e.getMessage());             }         }     }); } 

I have mocked:

PowerMockito.doNothing().when(accessService).generateCSVFile(billingDate); 

But when I verify:

verify(rbmPublicViewAccessService, timeout(100).times(1)).generateCSVFile(billingDate); 

It gives me as not invoked. Is this because it is invoked via separate thread, and is it possible to verify the methods called in different thread?

like image 932
kuhajeyan Avatar asked Jun 20 '13 06:06

kuhajeyan


People also ask

How do you verify a method called in Mockito?

Mockito verify() method can be used to test number of method invocations too. We can test exact number of times, at least once, at least, at most number of invocation times for a mocked method. We can use verifyNoMoreInteractions() after all the verify() method calls to make sure everything is verified.

Are Mockito mocks thread safe?

However Mockito is only thread-safe in healthy tests, that is tests without multiple threads stubbing/verifying a shared mock. Stubbing or verification of a shared mock from different threads is NOT the proper way of testing because it will always lead to intermittent behavior.

Which method in Mockito verifies that no interaction has happened with a mock in Java?

Mockito verifyZeroInteractions() method It verifies that no interaction has occurred on the given mocks. It also detects the invocations that have occurred before the test method, for example, in setup(), @Before method or the constructor.


2 Answers

It is very likely that the Runnable hasn't been executed yet by the asyncTaskExecutor when you verify the invocation, resulting in a verification error in your unit test.

The best way to fix this is to join on the generated thread and wait for execution before verifying the invocations.

If you cannot get the instance of the thread, a possible work around is to mock the asyncTaskExecutor and implement it so it will execute the runnable directly.

private ExecutorService executor;  @Before public void setup() {     executor = mock(ExecutorService.class);     implementAsDirectExecutor(executor); }  protected void implementAsDirectExecutor(ExecutorService executor) {     doAnswer(new Answer<Object>() {         public Object answer(InvocationOnMock invocation) throws Exception {             ((Runnable) invocation.getArguments()[0]).run();             return null;         }     }).when(executor).submit(any(Runnable.class)); } 
like image 200
Tom Verelst Avatar answered Oct 11 '22 18:10

Tom Verelst


I had the same issue and played around with the timeout argument http://javadoc.io/page/org.mockito/mockito-core/latest/org/mockito/Mockito.html#22 but with argument 0 like in

verify(someClass, timeout(0)).someMethod(any(someParameter.class)); 

And it works. I assume that the testing thread yields, and therefore the other thread has an opportunity to do its work, calling the mocks appropriately. Still it smells like a hack.

like image 29
Francis Martens Avatar answered Oct 11 '22 19:10

Francis Martens