2017-08-01 63 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