2017-08-01 65 views
1

我有一项计划每30分钟运行一次的任务。我使用ScheduledExecutorService进行计划。如何在Junit中测试ScheduledExecutorService异常处理?

我想测试(junit)ScheduledExecutorService的异常处理,以便当有抛出的异常时,线程不会因为异常而死亡。

我的代码:

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; 
    } 
} 

至于现在,我需要的功能,单元测试检查:

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 { 

      } 
     }; 
    } 
} 

回答

2

我觉得你在这里下去了错误的兔子洞。含义:当您检查javadoc为您所使用的方法,你会发现:

创建一个单线程执行程序,它可安排命令给定延迟后运行命令,或者定期地执行。 (但是请注意,如果单个线程关闭前的执行期间出现故障而终止了,如果需要执行后续任务的新一个将代替它。)

换句话说:你是问如何测试这是保证正在使用您正在使用的Java系统库。从这个意义上说,你正在浪费你的时间。

可能而是花时间改进你的代码,以便于测试。你看 - 当你的班级收到一个ExecutorService对象(而不是为自己创建一个)时,你可以在same thread executor中传递你的单元测试。突然之间,您的单元测试可以在一个线程上运行,这使得整个测试变得更加容易 - 因为它允许您在测试中摆脱睡眠声明。 (和那些睡眠语句是更多的问题比线程不重新启动的机会,虽然系统库保证你这样做)。

除此之外:您可运行已经被写入的方式,应该保证运行此代码线程从未模具(当然,这是有问题的赶上的Throwable)。但为了测试,我猜你只有需要另一个“测试提供者”,其中update()引发任何类型的异常。

+0

当它说“单线程终止”它是否也包含运行时异常?我的意思是我想确保它在运行时异常时不会终止线程。 – user3407267

+0

我增强了我的答案。希望有所帮助。 – GhostCat