2

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 {

            }
        };
    }
}
GhostCat
  • 137,827
  • 25
  • 176
  • 248
user3407267
  • 1,524
  • 9
  • 30
  • 57

1 Answers1

3

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.

Community
  • 1
  • 1
GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • when it says "single thread terminates" does it include runtime exception as well ? I mean I want to make sure that it doesn't kill the thread when there is a run time exception. – user3407267 Aug 01 '17 at 18:08
  • I enhanced my answer. Hope that helps. – GhostCat Aug 01 '17 at 19:08