2017-08-01 5 views
1

J'ai une tâche que j'ai prévu de lancer toutes les 30 minutes. J'ai utilisé ScheduledExecutorService pour planifier.Comment tester la gestion des exceptions ScheduledExecutorService dans Junit?

Je souhaite tester (junit) la gestion des exceptions pour ScheduledExecutorService de sorte que, lorsqu'une exception est levée, le thread ne meurt pas à cause de l'exception.

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

Pour le moment, mon chèque de test unitaire pour la fonctionnalité:

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 { 

      } 
     }; 
    } 
} 

Répondre

2

Je pense que vous allez dans le trou du lapin ne va pas ici. Signification: lorsque vous vérifiez l'javadoc pour la méthode que vous utilisez, vous trouverez:

Crée un exécuteur monothread qui peut programmer des commandes à exécuter après un délai donné, ou d'exécuter périodiquement. (Notez cependant que si ce thread unique se termine en raison d'une défaillance lors de l'exécution avant l'arrêt, un nouveau prendra sa place si nécessaire pour exécuter des tâches suivantes.)

En d'autres termes: vous demandez comment tester Quelque chose qui est garanti pour fonctionner par la bibliothèque système Java que vous utilisez. Et en ce sens, vous perdez votre temps.

Vous préférez peut-être passer votre temps à améliorer votre code pour le rendre plus facile à tester. Vous voyez - quand votre classe recevra un objet ExecutorService (au lieu de créer un pour lui-même), vous pouvez passer un same thread executor pour vos tests unitaires. Et tout d'un coup, vos tests unitaires peuvent s'exécuter sur un thread ce qui rend l'ensemble du test beaucoup plus facile - car il vous permet de vous débarrasser de vos sleep déclarations dans vos tests. (et ces instructions de sommeil sont beaucoup plus d'un problème que les chances que les threads ne sont pas redémarrés, bien que la bibliothèque du système vous le permet).

Au-delà: votre runnable est déjà écrit d'une manière qui devrait garantie que les discussions en cours d'exécution de ce code ne mourir (bien sûr, il est douteux pour attraper Throwable). Mais afin de tester cela, je suppose que vous seulement besoin d'un autre "fournisseur de test" où update() jette toute sorte d'exception. Quand il est dit "single thread aboutates", cela inclut-il aussi l'exception runtime?

+0

Je veux dire que je veux m'assurer qu'il ne tue pas le thread quand il y a une exception d'exécution. – user3407267

+0

J'ai amélioré ma réponse. J'espère que cela pourra aider. – GhostCat