I have a method like the following one :
void enact(@NonNull final Request request) { XInput input = this.xBuilder.buildInputPayload(request); final Thread componentThread = new Thread(()->this.component.runJob(input)); componentThread.start(); return; }
void testVTService_Success() { when(xBuilder.buildInputPayload(any(Request.class))).thenReturn(inputPayloadWithAllArguments); activity.enact(TestConstants.request); verify(component, times(1)). runJob(any(XInput.class)); //Verification }
Upon verification that the component.runJob() method is being executed it is throwing an error stating that Wanted but not invoked: component.runJob() Actually, there were zero interactions with this mock.
How do I fix this? And verify if the thread is starting & executing the runJob method?
Advertisement
Answer
Your test is running on one thread, and your code under test runs a new thread.
This means that your test verification runs before the runJob
method because of multithreading.
At that point the test saying “Wanted but not invoked” is correct (the test code ran, checked if the production method had ran, it had not … aand then in the background the production code ran (too late)).
Ideally you should separate the control of threading from the logic in your app. Wrap the Thread
in a ThreadFactory
, for real code you can pass an actual Thread, for test code you can pass an object that runs the code instantly (on the same thread).
Or (not recommended) you hack your test (this will help you understand):
void testVTService_Success() { when(xBuilder.buildInputPayload(any(Request.class))) .thenReturn(inputPayloadWithAllArguments); activity.enact(TestConstants.request); try { Thread.sleep(TimeUnit.SECONDS.toMillis(10)); } catch (Exception e) { assertTrue(false); } verify(component, times(1)). runJob(any(XInput.class)); }
Now your test will always take 10 seconds, but hopefully the production code doesn’t take 10 seconds to complete execution?
This is not ideal, like I said originally you would want to pull the Thread out of that Method, pass in some type of Factory to the class and pass a Fake object in the test. (Thus avoiding trying to test multithreaded code.)