ScheduledExecutorService doesn't works during my junit test - java

I am working on writing some junit test for my spring application. Below is my junit test that that calls afterPropertiesSet method of my InitializeFramework class that implements InitializingBean interface.
Below is the flow where my junit test calls afterPropertiesSet method and then that method will call initializeModel method within the same class, and then that method has a scheduler which will call getBundlesInfo method every few minutes. But somehow during my junit, getBundlesInfo method is not getting called at all.
#Test
public void testFramework() {
try {
InitializeFramework io = new InitializeFramework();
io.afterPropertiesSet();
} catch (Exception e) {
}
}
public class InitializeFramework implements InitializingBean {
private static long checkWithDBInterval = 1L;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
#Override
public void afterPropertiesSet() throws Exception {
try {
// other code here
initializeModel();
} catch (Exception e) {
}
}
private void initializeModel() {
final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(
new Runnable() {
public void run() {
try {
getBundlesInfo();
} catch(Exception ex) {
// log exception here
}
}
}, 0, checkWithDBInterval, TimeUnit.MINUTES);
}
// this method is not getting called from my junit test
protected static void getBundlesInfo() {
// some code here
// have put the breakpoint here..
}
}
Can anybody help me with this? What wrong I am doing here? but during my application run, this flow works perfectly fine and getBundlesInfo gets called... Only during junit it is not working..

This happens because your unit test exits before the scheduler executes your Runnable.
Do you want to test that afterPropertiesSet calls getBundlesInfo or do you want to test the repeated invocation of getBundlesInfo?
How does your unit test assert that getBundlesInfo got called? Or are you not there yet?
If you just want to see that getBundlesInfo is called, you either could make a direct call to it and increase the initialDelay of your scheduler to checkWithDBInterval, or stub getBundlesInfo with Mockito and/or Powermock to for example use a CountDownLatch to synchronize on.
Well or just wait a couple of seconds after the call to afterPropertiesSet and then check if getBundlesInfo was called (which you can do with Mockito also btw).
In any case, you might want to add code which calls shutdown on the executor service after the test is finished
Since you use Spring:
Consider using the provided Task Execution and Scheduling framework to schedule the repeated call to getBundlesInfo and having afterPropertiesSet directly call getBundlesInfo initially.
Anyway, here is an example with stubbing and using a CountDownLatch for the waiting part.
I also had to make getBundlesInfo non-static, as i couldnt quickly remember/find how to stub a static method.
import static org.mockito.Mockito.*;
import java.util.concurrent.*;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class StackOverflowTest
{
public static class ClassWithScheduler
{
private static long checkWithDBInterval = 1L;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( 1 );
public void entryPoint()
{
scheduler.scheduleAtFixedRate( new Runnable() {
public void run()
{
try
{
thisHasToBeCalled();
}
catch( Exception ex )
{
// log exception here
}
}
}, 0, checkWithDBInterval, TimeUnit.MINUTES );
}
protected void thisHasToBeCalled()
{
System.out.println( "thisHasToBeCalled was called" );
}
}
// since we are waiting on another thread either use a timed-wait (latch.await also
// has a variant which accepts a timeout) or use the timeout attribute of the
// #Test annotation
#Test( timeout = 5000L )
public void testCall() throws Exception
{
// create latch which this thread waits on and the scheduler thread
// notifies on
final CountDownLatch latch = new CountDownLatch( 1 );
// create instance
ClassWithScheduler instance = spy( new ClassWithScheduler() );
// stub thisHasToBeCalled to notify on the latch
doAnswer( new Answer<Void>() {
#Override
public Void answer( InvocationOnMock invocation ) throws Throwable
{
// call the real method
invocation.callRealMethod();
// notify waiting thread
latch.countDown();
System.out.println( "stub" );
return null;
}
} ).when( instance ).thisHasToBeCalled();
// execute
instance.entryPoint();
// wait for thread to call the stubbed method
latch.await();
// assert that the method was called /
verify( instance ).thisHasToBeCalled();
}
}

You will notice that if you change your getBundlesInfo() to something like
protected static void getBundlesInfo() {
System.out.println("ay");
}
and the TimeUnit you are using to TimeUnit.MILLISECONDS, that it will print as much as it can. For example, I got
ay
ay
ay
ay
This is because JUnit cleans up any threads running on the JVM before exiting. It kills/stops/interrupts them.

Related

How to test #Async Spring methods with junit?

I have an #Async method and want to test it with junit.
Problem: I want junit to fire all calls to the async method without blocking, so don't want for the outcome.
But in my following example, each call first waits for the async method to return, and then continue with the next incovation:
#Service
public class MainService {
#Autowired
private SubService sub;
#Async
public void processAsync() {
sub.run();
}
}
#SpringBootTest
public class MainServiceTest {
#Autowired
private MainService service;
#MockBean
private SubService sub;
#Test
public void testAsync() {
final CountDownLatch latch = new CountDownLatch(5);
when(sub.run()).then((answer) -> {
latch.countDown();
latch.await(); //return when latch is 0
return;
}
for (int i = 0; i<6; i++) {
//TODO this currently runs in sync. why?
service.processAsync();
}
}
}
I want all service calls to block until latch count reaches 0, and then continue the test.
But what I get is that the SubService is only called once, and then stucks inside the mocked Answer method.
Question: why are my service.process() calls inside the #Test method not fired 5x directly?
The follow clue is to let sub-method wait for a CountDownLatch. This way, all threads will first be started and wait inside the subroutine.
Then, inside the test method, release the latch, so that all methods continue:
#Test
public void testAsync() {
CountDownLatch waiter = new CountDownLatch(1);
when(sub.run()).then((answer) -> {
waiter.await();
return;
}
Stream.generate(() -> new Thread(() -> service.processAsync()))
.limit(6)
.forEach(Thread::start);
waiter.countDown(); //resumes all waiting threads
}

Mockito verify fails in second unit test

I am using Mockito together to JUnit to implement unit tests for a class in an Android project.The problem is that I call Mockito.verify in two consequent tests where the tests are exactly same (to make sure that I am using Mockito correctly) but the interesting thing is that verify in second test always fails.I suspect that some operations need to be done before each test using #before annotation or so, that I have missed.Here are some code snippet about what I am doing.
I use Android Studio 3.4.1, Mockito 2.7.22 and JUnit 4.12.
#Test
public void test_onStart_do_nothing() throws Exception {
ZConnectionService zConnectionService = new ZConnectionService();
ZConnection mockedZConnection = mock(ZConnection.class);
doNothing().when(mockedZConnection).connect();
zConnectionService.initConnection(mockedZConnection);
verify(mockedZConnection, times(1)).connect();
}
#Test
public void test_onStart_throw_IO_exceptioon() throws Exception {
ZConnectionService zConnectionService = new ZConnectionService();
ZConnection mockedZConnection = mock(ZConnection.class);
doNothing().when(mockedZConnection).connect();
zConnectionService.initConnection(mockedZConnection);
// Line above is the line that error message points to!
verify(mockedZConnection, times(1)).connect();
}
Here comes the function under test
public void initConnection(ZConnection connection) {
Log.d(TAG,"initConnection()");
if (mConnection == null) {
mConnection = connection;
}
if (!mActive) {
mActive = true;
if (mThread == null || !mThread.isAlive()) {
mThread = new Thread(new Runnable() {
#Override
public void run() {
// The code here runs in a background thread.
Looper.prepare();
mTHandler = new Handler();
try {
mConnection.connect();
} catch (IOException e) {
Intent i = null;
i = new Intent(ZConnectionService.UI_NOTCONNECTED);
i.setPackage(getApplicationContext().getPackageName());
getApplicationContext().sendBroadcast(i);
e.printStackTrace();
// Stop the services all together.
stopSelf();
}
Looper.loop();
}
});
mThread.start();
}
}
}
I expect that both tests should pass without any problem. In fact, both tests are passed when I ran them individually, but they fail when I run the whole suite and the error is:
Wanted but not invoked:
mockedZinkConnection.connect();
-> at com.app.z.ZConnectionServiceUnitTest.test_onStart_throw_IO_exceptioon(ZConnectionServiceUnitTest.java:207)
Actually, there were zero interactions with this mock.
I think the issue is a multithreading one.
When you call initConnection, it calls mConnection.connect() in a Thread
The problem you are having is that this Thread takes some time to complete and you end up calling verify(mockedZConnection, times(1)).connect(); before the Thread actually reached the connect() call.
A way to make sure about it is to join the Thread after you start it, it will wait until the Thread has finished before continuing:
mThread.start();
try {
mThread.join();
} catch (InterruptedException i) {
i.printStackTrace();
}
Now both tests should work.
This of course is not acceptable in the code, because it negated the use of a Thread. You will need an other way to test it.
A way I can think of would be to wait for the Thread to complete in your test before checking the mock:
#Test
public void test_onStart_throw_IO_exceptioon() throws Exception {
ZConnectionService zConnectionService = new ZConnectionService();
ZConnection mockedZConnection = mock(ZConnection.class);
doNothing().when(mockedZConnection).connect();
zConnectionService.initConnection(mockedZConnection);
// Wait for the Thread to complete
while(zConnectionService.mThread.isAlive()) {
Thread.sleep(100);
}
verify(mockedZConnection, times(1)).connect();
}
Tried and it works fine for me. Not sure it is a best practice though as you need to make public some internals of your class, which violates encapsulation
maybe having a package protected isThreadAlive() method on your ZConnectionService class could be acceptable
boolean isThreadAlive() {
return mThread.isAlive();
}
and the loop in the test
while(zConnectionService.isThreadAlive()) {
Thread.sleep(100);
}

How to test ScheduledExecutorService exception handling in Junit?

I have a task which I scheduled to run every 30 mins. I used ScheduledExecutorService to schedule.
I want to test(junit) the exception handling for ScheduledExecutorService such that when ever there is an exception thrown, the thread is not dying because of the exception.
My code :
public enum MonitorTask {
TIMER;
private final AtomicBoolean isPublishing = new AtomicBoolean(false);
private final long period = 18000000
public synchronized boolean initialize() {
return initialize(period, period);
}
/**
* #return true, if call was successful i.e. Timer task was scheduled
*/
boolean initialize(long delay, long period) {
if (isPublishing.get()) {
log.warn("Already monitoring for new feature data");
return false;
}
//execute on daemon thread
ScheduledExecutorService scheduledExecutorService =
Executors.newSingleThreadScheduledExecutor(runnable -> {
Thread thread = new Thread(runnable);
thread.setDaemon(true);
return thread;
}
);
Runnable runnableTask = () -> {
try {
DataPublisher.INSTANCE.update(DateTime.now());
} catch (Throwable e) {
log.warn("Failed to check for new Data!", e);
}
};
scheduledExecutorService.scheduleAtFixedRate(runnableTask, delay, period, TimeUnit.MILLISECONDS);
isPublishing.set(true);
return true;
}
}
As for now, my unit test check for the functionality:
public class MonitorTaskTest {
#Test
public void testInitialize() throws Exception {
AtomicInteger val = new AtomicInteger(0);
DataProvider provider = testProvider(val);
assertEquals(0, val.get());
// this should update val every 10 ms ( adds 1 to val )
Assert.assertTrue(MonitorTask.TIMER.initialize(0, 10));
assertEquals(0, val.get());
DataPublisher.INSTANCE.registerForNewData(provider, DateTime.now());
// wait for 3 updates
Thread.sleep(10 * 3);
Assert.assertTrue("Expected val to be >= 3 but is " + val.get(), val.get() >= 3);
}
#Before
public void setUp() {
DataPublisher.INSTANCE.clear();
}
private static DataProvider testProvider(final AtomicInteger ai) {
return new DataProvider() {
private AtomicInteger val = ai;
#Override public boolean update(DateTime dateTime) throws Exception {
val.incrementAndGet();
return true;
}
#Override public boolean exists(DateTime dateTime) {
return true;
}
#Override public void close() throws Exception {
}
};
}
}
I think you are going down the wrong rabbit hole here. Meaning: when you check the javadoc for the method you are using, you find:
Creates a single-threaded executor that can schedule commands to run after a given delay, or to execute periodically. (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.)
In other words: you are asking how to test something that is guaranteed to work by the Java system library you are using. And in that sense you are wasting your time.
You might rather spend time to improve your code to make it easier to test. You see - when your class would receive an ExecutorService object (instead of creating one for itself) you could pass in a same thread executor for your unit tests. And all of a sudden, your unit tests can run on one thread which makes the whole testing a lot easier - as it allows you to get rid of your sleep statements in your tests. (and those sleep statements are much more of a problem than chances that threads are not re-started although the system library guarantees you to do so).
Beyond that: your runnable is already written in a way that should guarantee that threads running this code never die (of course, it is questionable to catch Throwable). But in order to test that, I guess you only need another "test provider" where update() throws any kind of exception.

Use the run method to start a watcher Thread

I have a
ThreadPoolExecutor cachedPool = (ThreadPoolExecutor)Executors.newCachedThreadPool();
The cachededPool has to perform the following functionality in the main SimController class.
Run method for a watcher thread. Once per Second, check and call a function.
public void run(){
if(m.isChanged()){
m.toString();
}
}
But it only executes the run method once.
How can I make it run every second and create a watcher.
You can use ScheduledExecutorService.scheduleAtFixedRate() as suggested by Peter Lawrey in a comment, or you can do the following:
public void run() throws InterruptedException {
for( ;; ) {
if( m.isChanged() ) //hopefully m is thread-safe
m.toString(); //hopefully something more meaningful here
Thread.sleep( 1000 ); //1000 milliseconds is one second.
}
}
Note: if your run() method cannot throw InterruptedException, then you need to handle the InterruptedException that may be thrown by Thread.sleep(). A quick and dirty way to do this is to just say try{ ... } catch( InterruptedException e ) { throw new AssertionError( e ); } but if you want to do it the proper way, then be sure to read this: Handling InterruptedException in Java
The ScheduledExecutorService makes this pretty simple as this example, which prints the date every second, shows:
public class MonitorService {
public static void main(String[] a) throws Exception {
ScheduledExecutorService service =
Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(() -> {
System.out.println(LocalDateTime.now());
}, 0, 1, TimeUnit.SECONDS);
}
}
If you have multiple jobs to schedule in your system you would want to share the scheduled executor service among all tasks for efficiency.
If you are using Spring then you could also use #Scheduled task over a method to run a scheduled task.
#Component
#EnableScheduling
public class TestClass {
#Scheduled(fixedRate= 1000 , initialDelay = 18000)
public void TestMethod(){
// Do Something
} }

Unit Testing Multi thread Api

I am writing a Api that executes HTTP Request on a worker thread then call a method of a Callback-Handler when finish.
public class GriklyClient <E,T>{
private final IHttpRequest<E,T> request;
private final ResponseListener<T> response;
protected GriklyClient (IHttpRequest<E,T> request,ResponseListener<T> response)
{
this.request = request;
this.response = response;
}
/**
* Dispatch a thread to process
* HTTP Request.
*/
public void execute ()
{
Runnable thread = new Runnable()
{
public void run()
{
T result = (T) request.execute ();
response.response(result);
}
};
new Thread(thread).start();
}//end execute method
}
This is how a call to the ApI looks like:
Grikly grikly = new Grikly(developerKey);
grikly.addValidUserCredential(email,password);
grikly.fetchUser(1, new ResponseListener<User>() {
public void response(User result) {
// TODO Auto-generated method stub
System.out.println(result);
}
});
The problem I am having is Unit Testing. The Callback Handler is not being called in my Unit Test thus all my Test always pass even when they should fail.
private Grikly grikly = new Grikly (developerKey);
#Test
public void fetchUser ()
{
grikly.fetchUser(1, new ResponseListener<User>() {
public void response(User result) {
Assert.assertNotNull(result);
}
});
}//end fetchUser Test
How can I write a Unit test to test this Api?
Well, I guess your problem here is because your method fetchUser is an asynchonous method rather than a synchonous one which will not return until it have done its job.
So, the calling of grikly.fetchUser(... will return immediately(so does the test method fetchUser() w/o any sign of failure or success), while the 'lonely' thread you create in GriklyClient will keep running and finish its job by calling the callback method response in your new ResponseListener<User> and of course, nobody cares at that time.
IMO, either a CountdownLatch or a more general ReentrantLock with its Condition buddy can save your day. And tutorials talking about these two tools can be easily found using Google. Good luck with that.
EDIT:
On a second thought, if you wanna test the result that got passed to the callback method, it might be necessary to pass(or publish) it from the new thread you create to the test main thread(by save it to a lock guarded or volatile decorated field) and test it in the #Test annotated method, which in your case is the fetchUser().

Categories